异步设置 ReactJS 状态

Posted

技术标签:

【中文标题】异步设置 ReactJS 状态【英文标题】:Set ReactJS state asynchronously 【发布时间】:2014-09-23 21:32:44 【问题描述】:

如果您执行更新 componentWillMount 中状态的异步操作(如文档所说),但在异步调用完成之前组件已卸载(用户导航离开),您最终会尝试异步回调设置一个现在卸载的组件的状态,和一个

"Invariant Violation: replaceState(...): Can only update amounted or 安装组件。”

错误。

解决这个问题的最佳方法是什么?

谢谢。

【问题讨论】:

【参考方案1】:

您可以使用component.isMounted 方法在替换其状态之前检查组件是否实际附加到DOM。 Docs.

isMounted() 返回 true 如果组件被渲染到 DOM 中, false 否则。您可以使用此方法来保护异步调用 到setState()forceUpdate()

UPD:在你投反对票之前。这个答案是在 2 年前给出的。这就是当时做事的方式。如果您刚开始使用 React,请不要遵循此答案。使用componentDidMount 或您需要的任何其他生命周期挂钩。

【讨论】:

【参考方案2】:

isMounted()实际上是解决大多数问题的简单方法,但是,我认为这不是解决并发问题的理想解决方案。

现在想象一下,用户在许多按钮上点击的速度非常快,或者他的移动连接很差。 最终可能有 2 个并发请求处于挂起状态,完成后会更新状态。

如果您触发请求 1 然后请求 2,那么您会期望请求 2 的结果被添加到您的状态。

现在假设由于某种原因请求 2 在请求 1 之前结束,这可能会使您的应用程序不一致,因为它会显示 request2 结果然后请求 1,而您最后的“兴趣”实际上是在请求 1 的答案中。

要解决此类问题,您应该使用某种Compare And Swap 算法。基本上,这意味着在发出请求之前,您将某个对象节点置于状态,并且在请求完成时,如果要交换的节点在请求完成时仍然是您感兴趣的节点,则与引用相等性进行比较。

类似这样的:

var self = this;
var resultNode = ;
this.setState(result: resultNode);
this.getResult().then(function(someResult) 
    if ( self.state.result === resultNode ) 
        self.setState(result: someResult)
    
):

这样的话,如果用户点击快速按钮导致同一组件内的当前请求,您将不会遇到并发问题。

【讨论】:

【参考方案3】:

2016 年更新

不要开始使用isMounted,因为它将从 React 中删除,see the docs。

对于来自cmomponentWillMount 的异步调用引起的问题,最好的解决方案可能是将内容移至componentDidMount

有关如何正确解决此问题以及如何 需要在此处使用 isMounted 的更多信息:isMounted is an Antipattern

【讨论】:

以上是关于异步设置 ReactJS 状态的主要内容,如果未能解决你的问题,请参考以下文章

异步/等待 Reactjs

Reactjs - 为啥我不能设置状态?

Reactjs中的getCurentPosition()不更新状态

ReactJS 组件设置状态没有做任何事情?

Typescript & ReactJS 如何动态设置状态

ReactJs:在使用动态 Taglist 时使用道具设置初始状态