异步设置ReactJS状态
Set ReactJS state asynchronously
如果你做了一个异步操作来更新componentWillMount
中的状态(就像文档说的那样),但是在异步调用完成之前组件被卸载了(用户导航离开了),你最终会得到异步回调,试图在一个现在被卸载的组件上设置状态,并且
"不变量违反:replaceState(…):只能更新一个挂载的或安装组件。"
错误。
解决这个问题的最好方法是什么?
谢谢。
您可以使用component.isMounted
方法来检查组件是否实际上附加到DOM之前,替换它的状态。Docs .
isMounted()
返回true
如果组件被渲染到DOM,否则false
。您可以使用此方法来保护异步调用setState()
或forceUpdate()
.
UPD:在你投反对票之前。这个答案是两年前给出的。那是当时的一种做事方式。如果你刚刚开始使用React,不要遵循这个答案。使用componentDidMount
或者其他你需要的生命周期钩子
isMounted()
实际上是解决大多数问题的简单方法,然而,我不认为这是并发问题的理想解决方案。
现在想象一下,用户非常快速地点击了许多按钮,或者他的移动连接非常差。可能最后有2个并发请求处于挂起状态,并且在完成时将更新状态。
如果您触发请求1,然后触发请求2,那么您将期望请求2的结果被添加到您的状态。
现在想象一下,由于某种原因,请求2在请求1之前结束,这可能会使你的应用程序不一致,因为它将显示请求2的结果,然后是请求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的更多信息:
- 如何更改reactjs中外部/独立组件的状态或属性
- 从外部函数渲染后更改ReactJS类的状态
- ReactJS:使用浏览器按钮导航时保存状态
- reactjs-redux,是否可以有一个由2个组件使用的状态
- 是否可以在reactjs中设置多个状态变量
- 如果我不应该在组件WillUpdate中调用setState,如何更新状态(使用ReactJS)
- Reactjs:在修改对象之前,是否需要复制处于组件状态的对象
- 如何在reactjs中管理树组件中的状态
- 设置状态PubSub ReactJS和Rails
- 将状态传递到Ajax调用ReactJS和Rails中
- ReactJS-这个状态中的数组在删除时被正确更新,但结果是't,直到以后的状态发生变化
- ReactJS:如何在改变状态后立即更新组件
- 使用ReactJS使用Redux的简单状态更新事件
- ReactJS:比较shouldComponentUpdate上的道具和状态
- 在 ReactJs 状态上将项目添加到数组中,并超时以进行自我删除
- 状态未立即更新时的 ReactJS 表单验证
- Reactjs:如何从 chidren 更新父母的状态
- ReactJs:如何在渲染组件时传递初始状态
- ReactJS加载有状态数据,优化
- 如何正确处理双嵌套数组的状态(ReactJS + Redux)