当组件的setState函数被调用之后,会发生什么?

在代码中调用setState函数之后,React 会将传入的参数对象与组件当前的状态合并,然后触发所谓的调和过程(Reconciliation)。经过调和过程,React 会以相对高效的方式根据新的状态构建 React 元素树并且着手重新渲染整个UI界面。在 React 得到元素树之后,React 会自动计算出新的树与老树的节点差异,然后根据差异对界面进行最小化重渲染。在差异计算算法中,React 能够相对精确地知道哪些位置发生了改变以及应该如何改变,这就保证了按需更新,而不是全部重新渲染。

...
constructor(props) {
    super(props)
    this.state = {
        val: 0
    }
}
componentDidMount() {
    this.setState({val: this.state.val + 1});
    console.log("componentDidMount:"+this.state.val); 

    this.setState({val: this.state.val + 1});
    console.log("componentDidMount:"+this.state.val); 
    setTimeout(() => {
        this.setState({val: this.state.val + 1});
        console.log("componentDidMount setTimeout:"+this.state.val);
        this.setState({val: this.state.val + 1});
        console.log("componentDidMount setTimeout:"+this.state.val);
    })
}
componentDidUpdate() {
    console.log("componentDidUpdate:"+this.state.val);
}
...
// 打印结果
componentDidMount:0
componentDidMount:0
componentDidUpdate:1
componentDidUpdate:2
componentDidMount setTimeout:2
componentDidUpdate:3
componentDidMount setTimeout:3


setState源码

ReactComponent.prototype.setState = function(partialState, callback) {
    !(
        typeof partialState === "object" ||
        typeof partialState === "function" ||
        partialState == null
    )
        ? "development" !== "production"
            ? invariant(
                    false,
                    "setState(...): takes an object of state variables to update or a function which returns an object of state variables."
                )
            : _prodInvariant("85")
        : void 0;
    this.updater.enqueueSetState(this, partialState);
    if (callback) {
        this.updater.enqueueCallback(this, callback, "setState");
    }
};
  1. 调用enqueueSetState。该方法将我们传入的partialState添加到一个叫做_pendingStateQueue的队列中去存起来,然后执行一个enqueueUpdate方法。
  2. 如果存在callback就调用enqueueCallback将其存入一个_pendingCallbacks队列中存起来。然后我们来看enqueueUpdate方法。
function enqueueUpdate(component) {
    // ...
    if (!batchingStrategy.isBatchingUpdates) {
        batchingStrategy.batchedUpdates(enqueueUpdate, component);
        return;
    }
    dirtyComponents.push(component);
}
// 若 isBatchingUpdates 为 true,则把当前组件(即调用了 setState 的组件)放入 dirtyComponents 数组中;
// 否则 batchUpdate 所有队列中的更新。

var batchingStrategy = {
    isBatchingUpdates: false,

    batchedUpdates: function(callback, a, b, c, d, e) {
        // ...
        batchingStrategy.isBatchingUpdates = true;
        // Transaction(事务)
        // 一个所谓的 Transaction 就是将需要执行的 method 使用 wrapper 封装起来,
        // 再通过 Transaction 提供的 perform 方法执行。而在 perform 之前,
        // 先执行所有 wrapper 中的 initialize 方法;
        // perform 完成之后(即 method 执行后)再执行所有的 close 方法。
        // 一组 initialize 及 close 方法称为一个 wrapper

        transaction.perform(callback, null, a, b, c, d, e);
    }
};

由以上代码可知调用setState 将我们传入的partialState添加到一个叫做_pendingStateQueue的队列中去存起来,然后执行一个enqueueUpdate方法, 并把当前组件(即调用了 setState 的组件)放入 dirtyComponents 数组中在某一时刻做批量更新,所以console.log("componentDidMount:"+this.state.val)的结果为0。

this.setState(partialState1); 
this.setState(partialState2);

// 连续调用
// 事务中会将partialState1和partialState2合并处理
类似于 Object.assign({}, partialState1, partialState2)
constructor(props) {
  super(props);
  this.state = {
    val5: 0
  };
}
componentDidMount() {
  this.setState((state, props) => {
    return {
      val5: state.val5 + 1
    };
  });
  this.setState((state, props) => {
    return {
      val5: state.val5 + 1
    };
  });
  console.log("componentDidMount val5:" + this.state.val5);
}
componentDidUpdate() {
  console.log("componentDidUpdate val5:" + this.state.val5);
}
// 结果
componentDidMount val5:0
componentDidUpdate val5:2
 _processPendingState: function (props, context) {
     var inst = this._instance;    // _instance保存了Constructor的实例,即通过ReactClass创建的组件的实例
     var queue = this._pendingStateQueue;
     var replace = this._pendingReplaceState;
     this._pendingReplaceState = false;
     this._pendingStateQueue = null;

     if (!queue) {
       return inst.state;
     }

     if (replace && queue.length === 1) {
       return queue[0];
     }

     var nextState = _assign({}, replace ? queue[0] : inst.state);
     for (var i = replace ? 1 : 0; i < queue.length; i++) {
       var partial = queue[i];
       _assign(nextState, typeof partial === 'function' ? partial.call(inst, nextState, props, context) : partial);
     }

     return nextState;
}

for循环遍历了_pendingStateQueue中所有保存的状态,对于每一个状态进行处理,处理时首先判断保存的是function还是object。若是function,就在inst的上下文中执行该匿名函数,该函数返回一个代表新state的object,然后执行assign将其与原有的state合并;若是object,则直接与state合并。所以生成componentDidUpdate val5:2的结果

results for ""

    No results matching ""