如果您执行更新状态的异步操作componentWillMount
(如文档所说),但在异步调用完成之前组件已卸载(用户导航离开),您最终会遇到异步回调尝试设置状态现在卸载的组件,和一个
“不变违规:replaceState(...):只能更新已安装或已安装的组件。”
错误。
解决这个问题的最佳方法是什么?
谢谢。
如果您执行更新状态的异步操作componentWillMount
(如文档所说),但在异步调用完成之前组件已卸载(用户导航离开),您最终会遇到异步回调尝试设置状态现在卸载的组件,和一个
“不变违规:replaceState(...):只能更新已安装或已安装的组件。”
错误。
解决这个问题的最佳方法是什么?
谢谢。
您可以component.isMounted
在替换其状态之前使用方法检查组件是否实际附加到 DOM。文档。
isMounted()
true
如果组件被渲染到 DOM 中, 则返回,false
否则返回。您可以使用此方法来保护对setState()
或的异步调用forceUpdate()
。
UPD:在你投反对票之前。这个答案是在两年前给出的。这就是当时做事的方式。如果您刚开始使用 React,请不要遵循此答案。使用componentDidMount
或您需要的任何其他生命周期挂钩。
isMounted()
实际上是解决大多数问题的简单方法,但是,我认为这不是解决并发问题的理想解决方案。
现在想象一下,用户在许多按钮上点击的速度非常快,或者他的移动连接很差。最终可能有 2 个并发请求处于挂起状态,完成后将更新状态。
如果您触发请求 1 然后请求 2,那么您会期望请求 2 的结果被添加到您的状态。
现在想象由于某种原因请求 2 在请求 1 之前结束,这可能会使您的应用程序不一致,因为它会显示 request2 结果然后请求 1,而您最后的“兴趣”实际上是在请求 1 的答案中。
要解决此类问题,您应该使用某种比较和交换算法。基本上,这意味着在发出请求之前,您将某个对象节点置于状态,并且在请求完成时,如果要交换的节点在请求完成时仍然是您感兴趣的节点,则与引用相等性进行比较。
像这样的东西:
var self = this;
var resultNode = {};
this.setState({result: resultNode});
this.getResult().then(function(someResult) {
if ( self.state.result === resultNode ) {
self.setState({result: someResult})
}
}):
有了这样的东西,如果用户单击快速按钮导致同一组件内的当前请求,您将不会遇到并发问题。
2016 年更新
不要开始使用isMounted
,因为它将从 React 中删除,请参阅文档。
可能由异步调用引起的问题的最佳解决方案cmomponentWillMount
是将事物移至componentDidMount
.
有关如何正确解决此问题以及如何不需要在此处使用 isMounted 的更多信息: isMounted is an Antipattern