ReactJS并发SetState竞争条件

时间:2015-05-20 01:03:56

标签: reactjs race-condition setstate

我有这样的组件结构

<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();
);
}

我的问题是:

这是一个错误,多个simalteneous setState调用竞争条件,或者我在做错了而没​​有修改它?

2 个答案:

答案 0 :(得分:19)

您可能希望将函数传递给setState,这应该会消除此类竞争条件。类似的东西:

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

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

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

答案 1 :(得分:2)

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

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

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