Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
JTangming opened this issue May 25, 2019 · 2 comments
Open

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

JTangming opened this issue May 25, 2019 · 2 comments

Comments

@JTangming
Copy link
Owner

JTangming commented May 25, 2019

年初在面试相关候选人的时候总是会问到 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 生命周期方法来更新组件。

facebook/react#11527 (comment)

@kisurekeyvick
Copy link

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

@JTangming
Copy link
Owner Author

JTangming commented May 27, 2019

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

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants