ReactJS 并发 SetState 竞争条件

Posted

技术标签:

【中文标题】ReactJS 并发 SetState 竞争条件【英文标题】:ReactJS concurrent SetState race condition 【发布时间】:2015-08-01 01:05:51 【问题描述】:

我有这样的组件结构

<A>
    <B>
        <C/>
        <C/>
    </B>
    <D>
       <E/>
       <E/>
    </D>
</A>

想法是块 E 中组件上的操作由组件 A 的函数处理为 A 的状态,然后作为道具传递给 B 和 C。我知道,更好的方法是使用 Flux、pubsub-js 或其他 Store-message 系统,但希望有人能解释为什么按照我的理解正确的解决方案不起作用。

从组件 E 的多个实例中同时调用组件 A 的此函数会导致竞争条件只有一个状态更改(而不是每个函数调用都提供更改)

updateState(value,index)
   this.setState(update(this.state, 
        a: 
          [index]: 
            b: 
             $set: value
            
          
        
    )
);

这里的函数更新来自

import update from 'react/lib/update';

不符合 ReactJS 推荐做法的错误解决方案,但效果很好:

updateState(value,index)
   this.state.a[index].b=value;
   this.forceUpdate();
);

我的问题是:

这是一个错误,多个同时 setState 调用了一个竞争条件,还是我在不理解的情况下做错了什么?

【问题讨论】:

setState 是异步的,并且尽可能由 React 批处理以提高性能 您可能还想发送回调***.com/questions/25172850/… 【参考方案1】:

您可能希望将一个函数传递给setState,它应该会删除此类竞争条件。比如:

this.setState(currentState => 
  currentState.someProp++;
  return currentState;
);

即使您的应用程序的两个不同部分同时执行此操作,这两个函数仍将被调用并且someProp 将增加两次。

如果您改为这样做:this.setState(someProp: this.state.someProp + 1) 只会增加一次,因为在调用 setState 后不会直接更新 this.state.someProp。但是,当将函数传递给 setState 时,您将获得当前待处理状态作为参数,这使您可以选择像我的示例中那样仅递增,或者将您的突变与发生的任何其他突变合并。

【讨论】:

我相信update 函数应该做的完全一样。澄清一下 - 在我的情况下,我确实访问了覆盖它们的复杂状态对象的不同属性。 您不应更改传入该函数的对象。您应该返回一个具有更改状态的新对象。并且该参数称为prevState 而不是currentState,这也暗示了这一点。 到底发生了什么? :D 太棒了,谢谢【参考方案2】:

根据 React 文档,如第一个答案中所述,您可以传递一个函数来确保原子性的操作。问题是您不应该修改状态,而是在传递的函数中返回新值:

setState(function(previousState, currentProps) 
  return myInteger: previousState.myInteger + 1;
);

https://facebook.github.io/react/docs/component-api.html

【讨论】:

以上是关于ReactJS 并发 SetState 竞争条件的主要内容,如果未能解决你的问题,请参考以下文章

条件竞争漏洞

reactjs——解决setState异步问题

ReactJS , setState 发出 onChange 事件

ReactJs:获取无法读取未定义错误的属性“setState”[重复]

Axios ReactJS - 无法读取未定义的属性“setState”

ReactJS - setState 到多个元素