setState 为什么要设计成异步的?
来自 Dan 的解释:
- 保证内部的一致性
即使 state 是同步更新,props 也不是。(你只有在父组件重新渲染时才能知道 props)
- 性能优化
将 state 的更新延缓到最后批量合并再去渲染对于应用的性能优化是有极大好处的,如果每次的状态改变都去重新渲染真实 dom,那么它将带来巨大的性能消耗。
setState 并不能保证同步,可能是异步的
- 合成事件与生命周期钩子函数中 setState 是异步的。
- 原生事件和定时器事件中 setState 是同步的。
setState 更新过程
- 每次调用 setState 时,会将 setState 传入的
partialState
参数存储当前组件实例的 state 暂存队列中。 - 判断当前 React 是否处于批量更新状态,如果是,将当前组件加入待更新的组件队列 dirtyComponent 中。
- 如果未处于批量更新状态,将批量更新状态标识
isBatchingUpdate
设为true
,用事务调用前一步方法,保证当前组件加入到待更新组件队列中。 - 调用事务的
warpper
方法,遍历待更新组件依次执行更新。 - 执行生命周期
componentWillReceiveProps
。 - 将组件的state暂存队列中的 state 进合并,获得最终要更新的 state 对象,并将队列置为空。
- 执行生命周期
componentShouldUpdate
,根据返回值判断是否要继续更新。 - 执行生命周期
componentWillUpdate
。 - 执行真正的更新,render。
- 执行生命周期
componentDidUpdate
。
总结
setState
的 “异步”并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,形式了所谓的“异步”。