Updating a local state and a shared state in one stroke

时间:2016-07-11 22:29:45

标签: reactjs flux

Consider a component in React which has its own state and also uses some shared state (shared states are stored within a Store).

Here's a sample component for better understanding the question:

var ControllerView = React.createClass({
  getInitialState: function() {
    return {privateState: 1, sharedState: -1};
  },

  componentDidMount: function() {
    Store.addChangeListener(this._onChange);
  },

  componentWillUnmount: function() {
    Store.removeChangeListener(this._onChange);
  },

  _onChange: function() {
    this.setState({
      privateState: this.state.privateState,
      sharedState: Store.getSharedState()
    });
  }

  stepForward: function() {
    this.setState({
      privateState: this.state.privateState + 1,
      sharedState: this.state.sharedState
    });
    Action.decrease();
  },

  render: function() {
    return (
      <div>
        <button onClick={this.stepForward}>Go forth with private and shared state</button>
        <div>Private State: {this.state.privateState}</div>
        <div>Shared State: {this.state.sharedState}</div>
      </div>
    );
  }
});

As you can see in the given code, there's a button which pressing it will result in changing both private state and shared state. A private state can simply be updated by calling the setState method. But following the Flux architecture, updating a store should go through actions. That's why there's a Action.decrease();.

Just a recap of what will happen when an action is called;

  1. The action method called will come up with the new data (either through calculation or calling a service, in my question it doesn't matter how you come up with the new data).
  2. Once the action has got the new data, it will dispatch it so any store interested in it and they will pick it up and store it.
  3. After any store saves the data, it will emit a change notifying any component registered within that store to pick up the new data. This is when the component's _onChange is called.

So when the button is pressed, the component's state will update twice, once to update the private state and the second time when _onChange is called to update the shared state. These two setState calls happen one after the other in one thread.

What I experienced is that in such cases only the last setState will apply and the previous ones are discarded. My question is how to overcome this problem?

1 个答案:

答案 0 :(得分:0)

调用setState时,应该只包含实际更新的属性 - 状态中的其他属性将保持不变。您正在看到这样一个事实:当调用setState时,this.state不会立即更新,而只会在实际的反应渲染开始后(紧接在componentWillUpdate()之后和render()之前)。因此,当您调用第二个setState时,您将使用旧值替换privateState的新值(它仍保留在this.state中,直到渲染发生)。因此,您的代码应如下所示:

_onChange: function() {
  this.setState({
    sharedState: Store.getSharedState()
  });
}

stepForward: function() {
  this.setState({
    privateState: this.state.privateState + 1,
  });
  Action.decrease();
}