你可以在不调用 setState 的情况下强制 React 组件重新渲染吗?
我有一个外部(对于组件而言)可观察对象,我想监听其变化。当对象更新时,它会发出更改事件,然后我想在检测到任何更改时重新渲染组件。
使用顶级
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>
)
}
}
单击按钮会在内部调用
this.render()
,但这并不是真正导致渲染发生的原因(您可以看到这种情况,因为
{Math.random()>
创建的文本没有变化)。但是,如果我仅调用
this.setState()
而不是
this.render()
,它就可以正常工作。
所以我想我的问题是: React 组件是否 需要 具有状态才能重新渲染?有没有办法强制组件按需更新而不改变状态?
在类组件中,您可以调用
this.forceUpdate()
来强制重新渲染。
文档: https://facebook.github.io/react/docs/component-api.html
在函数组件中,没有
forceUpdate
的等效方法,但您可以
设计一种使用
useState
钩子强制更新的方法
。
forceUpdate
应该避免,因为它偏离了 React 的思维方式。React 文档引用了
forceUpdate
可能被使用的情况:
By default, when your component's state or props change, your component will re-render. However, if these change implicitly (eg: data deep within an object changes without changing the object itself) or if your render() method depends on some other data, you can tell React that it needs to re-run render() by calling forceUpdate().
但是,我想提出这样的想法:即使对象嵌套很深,
forceUpdate
也是不必要的。通过使用不可变数据源,跟踪更改变得很便宜;更改总是会产生一个新对象,因此我们只需要检查对该对象的引用是否已更改。您可以使用库
Immutable JS
将不可变数据对象实现到您的应用中。
Normally you should try to avoid all uses of forceUpdate() and only read from this.props and this.state in render(). This makes your component "pure" and your application much simpler and more efficient. forceUpdate()
更改要重新呈现的元素的键即可。通过状态在您的元素上设置 key prop,然后在您想要更新时设置状态以获得新键。
<Element key={this.state.key} />
然后发生变化,您重置了密钥
this.setState({ key: Math.random() });
我想指出的是,这将替换密钥正在更改的元素。这可能有用的一个例子是当您有一个文件输入字段,您想在图片上传后重置它。
虽然对 OP 问题的真正答案是
forceUpdate()
,但我发现这个解决方案在不同情况下很有用。我还想指出,如果您发现自己使用
forceUpdate
,您可能需要检查您的代码并看看是否还有其他方法可以做。
注意 1-9-2019:
上述(更改密钥)将完全替换元素。如果您发现自己正在更新密钥以使更改发生,则您的代码中的其他地方可能存在问题。在 key 中使用
Math.random()
将在每次渲染时重新创建元素。我不建议像这样更新 key,因为 React 使用 key 来确定重新渲染事物的最佳方式。
在 2021 年和 2022 年,这是强制更新 React 函数式组件的 官方方法 。
const [, forceUpdate] = useReducer(x => x + 1, 0);
function handleClick() {
forceUpdate();
}
我知道 OP 是针对类组件的。但这个问题是在 2015 年提出的,现在有了钩子,许多人可能会在函数式组件中搜索
forceUpdate
。这点是为他们准备的。
2022 年 4 月 18 日编辑
强制更新组件通常是一种不好的做法。
可能导致需要使用强制更新的几个原因。
- 在必须使用状态变量的地方不使用状态变量 - local、redux、context。
- 您尝试访问并期望更新/更改的状态对象中的字段在对象或数组中嵌套得太深。甚至 Redux 也建议维护平面对象或数组。如果复杂对象中只有一个字段值发生变化,React 可能无法弄清楚状态对象已更改,因此它不会更新组件。保持状态平坦和简单。
- 列表项上的键,如另一个答案中所述。事实上,这也可能导致其他意外行为。我见过一些列表,其中的项目被重复渲染(重复),因为键不相同或键完全缺失。始终要求后端团队尽可能发送唯一的 ID!避免使用数组索引作为键。不要尝试使用 nanoid、uuid 或随机在前端创建唯一的 ID。因为使用上述方法创建的 ID 会在每次组件更新时发生变化(提供给列表的键需要是静态的,并且每次渲染时都相同)。创建唯一的 ID 通常是后端关注的问题。尽量不要把这个要求带到前端。前端的责任只是绘制后端返回的数据,而不是动态创建数据。
- 如果您的 useEffect、useCallback 依赖数组没有设置正确的值。使用 ESLint 来帮助您解决这个问题!此外,这是 React 中内存泄漏的最大原因之一。在返回回调中清理您的状态和事件监听器以避免内存泄漏。因为这种内存泄漏很难调试。
- 始终关注控制台。它是你工作中最好的朋友。解决控制台中出现的警告和错误可以修复很多令人讨厌的事情 - 您甚至没有意识到的错误和问题。
我记得我做错了几件事。希望它有所帮助..