JTangming / blog

My repository on GitHub.
Other
53 stars 0 forks source link

关于 React setState,你了解多少? #11

Open JTangming opened 5 years ago

JTangming commented 5 years ago

年初在面试相关候选人的时候总是会问到 setState,其中不少人含糊其辞,没有很好的理解,这里再梳理记录一下吧。

setState 的基本用法

当组件 state 数据有变更的时候,通过 setState(updater, callback) 这个方法来告诉组件更新数据,即能驱动组件的更新过程,触发 componentDidUpdate、render 等一系列生命周期函数的调用,如有需要则重新渲染。该方法是异步执行的过程,特点是批量执行且通过一次更新来确保性能,正因为它是异步执行的,在使用setState 改变状态之后,通常立刻通过 this.state 去拿最新的状态往往是拿不到的。举个例子:

addCount = () => {
    this.setState({ index: this.state.count + 1 });
    this.setState({ index: this.state.count + 1 });
}

在以上代码中,调用一个累加方法,同步调用两次 setState,其效果最终只是+1,如果想获取最新的 state 的话可以在componentDidUpdate 或者 setState 的回调函数里获取,也可以通过第一个参数 return function 的方式,具体代码实例如下:

addCount = () => {
    this.setState((prevState, props) => {
      return {count: prevState.count + 1};
    });
    this.setState((prevState, props) => {
      return {count: prevState.count + 1};
    });
}

深入理解 setState

setState 通过一个队列机制来实现 state 更新,当执行 setState() 时,会将需要更新的 state 浅合并后放入状态队列,而不会立即更新 state,通过队列机制来批量更新 state。

这里记录一下其详细过程:

1、调用 setState 方法,其内部判断第一个参数是否是 Object 或 Function,随后调用 enqueueSetState; 2、通过查看 enqueueSetState 方法的源码,其主要是做了两件事: 将新的 partialState 入队(_pendingStateQueue 数组中),执行 enqueueUpdate;

enqueueSetState: function(publicInstance, partialState, ...) {
  var internalInstance = getInternalInstanceReadyForUpdate(publicInstance);
  if (internalInstance) {
    (internalInstance._pendingStateQueue || (internalInstance._pendingStateQueue = [])).push(partialState), 
    enqueueUpdate(internalInstance);
  }
}

setState 是通过 enqueueUpdate 来执行 state 更新的,那 enqueueUpdate 是如何实现更新 state 的?继续往下走。 3、enqueueUpdate 如果当前正处于创建/更新组件的过程,就不会立刻去更新组件,而是先把当前的组件放在 dirtyComponent 里,这里也很好的解释了上面的例子,不是每一次的 setState 都会更新组件。否则执行 batchedUpdates 进行批量更新组件; img

贴一下以上 3 的源码助于理解其中的过程,如下:

function enqueueUpdate(component) {
 // ...  
 if (!batchingStrategy.isBatchingUpdates) {
    batchingStrategy.batchedUpdates(enqueueUpdate, component);
    return;
  }

  dirtyComponents.push(component);
}

4、batchedUpdates 是将当次所有的 dirtyComponent 遍历,执行其 updateComponent 来更新组件,如调用 componentDidUpdate 生命周期方法来更新组件。

https://github.com/facebook/react/issues/11527#issuecomment-360199710

kisurekeyvick commented 5 years ago

问一下你所描述的setState,它react版本是多少?

JTangming commented 5 years ago

问一下你所描述的setState,它react版本是多少?

16.0.0-alpha.12 ps:之前梳理的不够仔细,有些描述不清楚的,重新 update 了一下(2019年07月25日更新