正确处理多个连续状态更新

Proper handling of multiple sequential state updates

本文关键字:状态 更新 连续 正确处理      更新时间:2023-09-26

这个例子有点做作,但请耐心等待。假设我在React组件中有两个成员函数:

var OrderApp = React.createClass({
    getInitialState: function() {
        return {
            selectedOrders: {},
            selectedLineItems: {}
        };
    },
    setOrderSelected: function(order, newSelectedState) {
        var mutation = {};
        mutation[order.id] = {$set: newSelectedState};
        var newSelectedOrders = React.addons(this.state.selectedOrders, mutation);
        _.each(order.lineItems, function(lineItem) {
            setLineItemSelected(lineItem, newSelectedState);
        });
        this.setState({selectedOrders: newSelectedOrders});
    },
    setLineItemSelected: function(lineItem, newSelectedState) {
        var mutation = {};
        mutation[lineItem.id] = {$set: newSelectedState};
        var newSelectedLineItems = React.addons(this.state.selectedLineItems, mutation);
        this.setState({seelctedLineItems: newSelectedLineItems});
    }
});

在调用OrderApp.setOrderSelected(order,true)完成时,在我的组件状态中,只有最后一个lineItem selected状态似乎发生了更改。我猜这是因为React正在批处理对setState的调用,所以当我调用时

var newSelectedLineItems = React.addons(this.state.selectedLineItems, mutation);

在第二个函数中,我每次都会获取原始状态,所以只有最后一个突变生效。

我应该收集父函数中的所有状态突变,并且只调用setState一次吗?这对我来说有点笨拙,我想知道我是否错过了一个更简单的解决方案。

在组件内的给定执行线程中,不应多次调用this.setState

所以你有几个选择:

使用forceUpdate而不是setState

您不必使用this.setState-您可以直接修改状态,并在完成后使用this.forceUpdate

这里要记住的主要一点是,一旦开始直接修改this.state,就应该将其视为受污染。IE:在调用this.forceUpdate之前,不要使用您知道已修改的状态或属性。这通常不是问题。

当您处理this.state中的嵌套对象时,我绝对喜欢这种方法。就我个人而言,我不是React.addons.update的超级粉丝,因为我觉得它的语法非常笨拙。我更喜欢直接修改forceUpdate

创建一个传递的对象,直到最终在setState中使用它

收集所有更改的对象,在执行线程结束时传递给this.setState

不幸的是,这是浅合并的一个问题。您必须收集更新,并一次性应用它们。

觉得有点笨重

这是一个非常好的迹象,表明您应该使用mixin!这个代码看起来很糟糕,但当你使用它时,你可以假装它看起来很漂亮

var React = require('react/addons');
var UpdatesMixin = {
    componentDidMount: function(){
        this.__updates_list = [];
    },
    addUpdate: function(update){
        this.__updates_list.push(update);
        if (this.__updates_list.length === 1) {
         process.nextTick(function(){
          if (!this.isMounted()) {
            this.__updates_list = null;
            return;
          }
          var state = this.__updates_list.reduce(function(state, update){
            return React.addons.update(state, update);
          }, this.state);
          this.setState(state);
          this.__updates_list = [];     
        }.bind(this));
      }
    }
};

中的必需

它缓冲所有同步发生的更新,将它们应用于this.state,然后执行setState。

用法如下(完整演示请参阅requirebin)。

this.addUpdate({a: {b: {$set: 'foo'}};
this.addUpdate({a: {c: {$set: 'bar'}};

有些地方可以对其进行优化(例如,通过合并更新对象),但您可以稍后在不更改组件的情况下进行优化。