Phi*_*ton 608 reactjs react-jsx
我有一个外部(对组件),可观察的对象,我想听取更改.当对象更新时,它会发出更改事件,然后我想在检测到任何更改时重新呈现组件.
使用顶级React.render
这是可能的,但在一个组件中它不起作用(这有一定意义,因为该render
方法只返回一个对象).
这是一个代码示例:
export default class MyComponent extends React.Component {
handleButtonClick() {
this.render();
}
render() {
return (
<div>
{Math.random()}
<button onClick={this.handleButtonClick.bind(this)}>
Click me
</button>
</div>
)
}
}
Run Code Online (Sandbox Code Playgroud)
单击按钮会在内部调用this.render()
,但这不是实际导致渲染发生的原因(您可以看到此操作因为创建的文本{Math.random()}
不会更改).但是,如果我只是打电话this.setState()
而不是this.render()
,它可以正常工作.
所以我想我的问题是: React组件需要有状态才能重新渲染吗?有没有办法强制组件按需更新而不改变状态?
Cro*_*rob 696
在您的组件中,您可以调用this.forceUpdate()
强制重新呈现.
文档:https://facebook.github.io/react/docs/component-api.html
piz*_*r0b 301
forceUpdate
应该避免,因为它偏离了React的心态.React文档引用了一个forceUpdate
可能使用的示例:
默认情况下,当组件的状态或道具发生更改时,组件将重新呈现.但是,如果这些隐式更改(例如:对象内部的数据更改而不更改对象本身)或者如果render()方法依赖于其他一些数据,则可以告诉React需要通过调用重新运行render()强制性升级().
但是,我想提出一个想法,即使使用深层嵌套的对象,forceUpdate
也是不必要的.通过使用不可变数据源,跟踪变化变得便宜; 更改将始终生成一个新对象,因此我们只需要检查对象的引用是否已更改.您可以使用库Immutable JS在您的应用程序中实现不可变数据对象.
通常你应该尽量避免使用forceUpdate(),只能在render()中读取this.props和this.state.这使您的组件"纯粹",您的应用程序更简单,更高效.https://facebook.github.io/react/docs/component-api.html#forceupdate
更改要重新渲染的元素的键将起作用.通过状态在元素上设置关键支柱,然后在您想要更新设置状态以获得新密钥时.
<Element key={this.state.key} />
Run Code Online (Sandbox Code Playgroud)
然后发生更改并重置密钥
this.setState({ key: Math.random() });
Run Code Online (Sandbox Code Playgroud)
我想要指出,这将取代密钥正在改变的元素.这可能有用的一个示例是当您有一个文件输入字段,您希望在图像上载后重置.
虽然OP问题的真正答案是forceUpdate()
我发现这个解决方案在不同情况下有所帮助.我还要注意,如果您发现自己正在使用forceUpdate
,可能需要查看您的代码并查看是否有其他方法可以执行操作.
说明1-9-2019:
以上(更改键)将完全取代元素.如果您发现自己更新密钥以进行更改,则可能在代码中的其他位置存在问题.使用Math.random()
in键将为每个渲染重新创建元素.我不建议像这样更新密钥,因为react使用密钥来确定重新渲染事物的最佳方法.
Qwe*_*rty 63
实际上,forceUpdate()
是唯一正确的解决方案,因为如果在其中简单地返回实现额外的逻辑,则setState()
可能不会触发重新渲染.shouldComponentUpdate()
false
调用
forceUpdate()
将导致render()
在组件上调用,跳过shouldComponentUpdate()
.更多...
setState()
除非实现条件渲染逻辑,否则将始终触发重新渲染shouldComponentUpdate()
.更多...
forceUpdate()
可以从您的组件中调用 this.forceUpdate()
vij*_*jay 34
forceUpdate
做以下事情错误的方法:不要使用索引作为关键
this.state.rows.map((item, index) =>
<MyComponent cell={item} key={index} />
)
Run Code Online (Sandbox Code Playgroud)
正确的方法:使用数据id作为密钥,它可以是一些guid等
this.state.rows.map((item) =>
<MyComponent item={item} key={item.id} />
)
Run Code Online (Sandbox Code Playgroud)
所以通过这样的代码改进,你的组件将是独一无二的并自然地呈现
gce*_*edo 32
当您希望两个React组件进行通信时,它们不受关系(父子)的约束,建议使用Flux或类似的体系结构.
你想要做什么是监听的变化观察到的部分店面,其中包含模型及其接口,并保存引起渲染改变的数据state
在MyComponent
.当商店推送新数据时,您可以更改组件的状态,从而自动触发渲染.
通常你应该尽量避免使用forceUpdate()
.从文档:
通常你应该尽量避免使用forceUpdate(),只能在render()中读取this.props和this.state.这使您的应用程序更简单,更高效
Tom*_*dil 29
2021 年,这是强制更新 React 功能组件的官方方式。
const [, forceUpdate] = useReducer(x => x + 1, 0);
function handleClick() {
forceUpdate();
}
Run Code Online (Sandbox Code Playgroud)
我知道 OP 是用于类组件的。但是这个问题是在 2015 年提出的,现在钩子可用,许多人可能会forceUpdate
在功能组件中搜索。这一点是给他们的。
Jas*_*ing 14
当我开始使用反应时,我正在将我的数据存储在状态中我不得不这样做以进行渲染.那是非常错误的.事实证明,如果你推出一些简单的不可变商店,你甚至可以避免做像Flux和Redux这样复杂的事情.
用于继承和处理商店更新的BaseView类
import React, { Component } from 'react'
export default function(/* store1, store2, store3... */) {
const storeArgs = Array.prototype.slice.call(arguments)
return function(WrappedComponent) {
return class WithStore extends Component {
constructor(props) {
super(props)
this.state = {
lastUpdated: Date.now()
}
this.stores = storeArgs
}
_onChange = () => {
this.setState({ lastUpdated: Date.now() })
}
componentWillMount = () => {
this.stores && this.stores.forEach(store => {
// each store has a common change event to subscribe to
store.on('change', this._onChange)
})
}
componentWillUnmount = () => {
this.stores && this.stores.forEach(store => {
store.off('change', this._onChange)
})
}
render() {
return <WrappedComponent
lastUpdated={this.state.lastUpdated}
{...this.props} />
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
如何使用
import React, { Component } from 'react'
import { View, Text, Button } from 'react-native'
import withStores from './withStores'
import userStore from './stores/users'
class MyView {
_increaseUserCount = () => {
userStore.setState({ userCount: userStore.state.count + 1 })
}
render() {
return (
<View>
<Text>User count: {userStore.state.count}</Text>
<Button
title="Increase User Count"
onPress={this._increaseUserCount}
/>
</View>
)
}
}
export default withStores(userStore)(MyView)
Run Code Online (Sandbox Code Playgroud)
Simple Store类示例
var ee = require('event-emitter')
export default class Store {
constructor() {
this._state = {}
this._eventEmitter = ee({})
}
get state() {
return this._state
}
setState(newState) {
this._state = {...this._state, ...newState}
this._eventEmitter.emit('change')
}
on(ev, fn) {
this._eventEmitter.on(ev, fn)
}
off(ev, fn) {
this._eventEmitter.off(ev, fn)
}
}
Run Code Online (Sandbox Code Playgroud)
将实例存储为单例
import Store from './Store'
const myStore = new Store()
export default myStore
Run Code Online (Sandbox Code Playgroud)
我认为这会消除较小应用程序所需的所有苛刻框架.尽管与Immutable.js结合使用redux用于中到大的.
更新 您应该查看React中"钩子"的最新发展.这看起来非常简洁.
https://reactjs.org/docs/hooks-intro.html
Kyl*_*ker 13
所以我想我的问题是:React组件需要有状态才能重新渲染吗?有没有办法强制组件按需更新而不改变状态?
其他答案试图说明你怎么做,但重点是你不应该.即使是改变关键的黑客解决方案也忽略了这一点.React的力量放弃了控制手动管理什么东西应该渲染,而只是关于你自己应该如何映射输入.然后提供输入流.
如果你需要手动强制重新渲染,你几乎肯定不会做正确的事情.
有几种方法可以重新渲染组件:
最简单的解决方案是使用 forceUpdate() 方法:
this.forceUpdate()
Run Code Online (Sandbox Code Playgroud)
另一种解决方案是在 state(nonUsedKey) 中创建未使用的密钥并调用 setState 函数并更新此 nonUsedKey:
this.setState({ nonUsedKey: Date.now() } );
Run Code Online (Sandbox Code Playgroud)
或者重写所有当前状态:
this.setState(this.state);
Run Code Online (Sandbox Code Playgroud)
道具更改还提供组件重新渲染。
你可以通过几种方式做到这一点:
1、使用forceUpdate()
方法:
使用该方法时可能会出现一些故障forceUpdate()
。一个例子是它会忽略该shouldComponentUpdate()
方法,并且无论是否shouldComponentUpdate()
返回 false 都会重新渲染视图。因此,应尽可能避免使用forceUpdate()。
2.将this.state传递给setState()
方法
以下代码行克服了上一个示例的问题:
this.setState(this.state);
Run Code Online (Sandbox Code Playgroud)
实际上,这一切都是用当前状态覆盖当前状态,从而触发重新渲染。这仍然不一定是最好的方法,但它确实克服了使用 forceUpdate() 方法可能遇到的一些问题。
我们可以使用 this.forceUpdate() 如下。
class MyComponent extends React.Component {
handleButtonClick = ()=>{
this.forceUpdate();
}
render() {
return (
<div>
{Math.random()}
<button onClick={this.handleButtonClick}>
Click me
</button>
</div>
)
}
}
ReactDOM.render(<MyComponent /> , mountNode);
Run Code Online (Sandbox Code Playgroud)
即使您使用 setState 重新渲染组件,DOM 中的元素“Math.random”部分也只会更新。
这里的所有答案都是正确的,补充了理解问题。我们知道,在不使用 setState({}) 的情况下重新渲染组件是通过使用forceUpdate()。
上面的代码使用 setState 运行,如下所示。
class MyComponent extends React.Component {
handleButtonClick = ()=>{
this.setState({ });
}
render() {
return (
<div>
{Math.random()}
<button onClick={this.handleButtonClick}>
Click me
</button>
</div>
)
}
}
ReactDOM.render(<MyComponent /> , mountNode);
Run Code Online (Sandbox Code Playgroud)
为了完整起见,您还可以在功能组件中实现这一点:
const [, updateState] = useState();
const forceUpdate = useCallback(() => updateState({}), []);
// ...
forceUpdate();
Run Code Online (Sandbox Code Playgroud)
或者,作为可重复使用的钩子:
const useForceUpdate = () => {
const [, updateState] = useState();
return useCallback(() => updateState({}), []);
}
// const forceUpdate = useForceUpdate();
Run Code Online (Sandbox Code Playgroud)
参见:https : //stackoverflow.com/a/53215514/2692307
请注意,使用强制更新机制仍然是不好的做法,因为它违背了反应的心态,所以如果可能的话仍然应该避免。
归档时间: |
|
查看次数: |
716482 次 |
最近记录: |