beizhu
type
Post
status
Published
date
Jun 30, 2020
slug
summary
setState 的合并是通过队列实现的。通过创建一个队列来保存每次 setState 的数据,然后每隔一段时间,清空和这个队列并渲染组件。在 React 的 setState 中,利用 JavaScript 的事件循环机制对多个 setState 调用进行合并。首先创建一个队列保存每次 setState 的数据,在一次事件循环的所有同步任务之后,清空着队列,将队列中的所有 setState 进行合并,并进行一次性更新渲染。这样在一次事件循环的,最多只会执行一次合并操作,并且只会渲染一次组件。
tags
React
category
技术
icon
password
setState
setState立马执行之后,是无法直接获取到最新的state的,需要经过React对state的所有改变进行合并处理之后,才会去计算新的虚拟dom,再根据最新的虚拟dom去重新渲染真实dom。
结果
React 其实会维护着一个 state 的更新队列,每次调用 setState 都会先把当前修改的 state 推进这个队列,在最后,React 会对这个队列进行合并处理,然后去执行回调。根据最终的合并结果再去走下面的流程(更新虚拟dom,触发渲染)。
setState为什么要设计成“异步”的,因为
setState()之后无法立马获取最新的 state,给人的感觉便是异步去设置状态。也确实是有异步的感觉。合成事件
React为了解决跨平台,兼容性问题,自己封装了一套事件机制,代替了原生的事件,像在jsx中常见的onClick、onChange这些都是合成事件
原生事件
原生事件是指非React合成事件,原生自带的事件监听addEventListener,或者也可以用原生js,jquery直接document.querySelector().onclick 这种绑定事件的形式都属于原生事件。
点击执行,点一点理解就很清楚了

结论
下面的异步是带引号的
- setState 只在合成事件和钩子函数中的是异步的,在原生事件和setTimeout中都是同步的
- setState 的异步并不是说内部由异步代码实现,其实本身执行的过程中和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,形成了所谓的异步,当然可以通过第二个参数setState(partialState, callback)中的callback拿到更新后的结果
- setState 的批量更新优化也是建立在异步(合成事件,钩子函数)只上的,在原生事件和setTimeout中不会批量更新,在异步中如果对同一个值进行多次setTimeout,setState的批量更新策略会对其进行覆盖,取最后一次的执行,如果是同事setState对个不同的值,在更新时会对其进行合并批量更新
20210107补充
setState 异步的,性能优化过程中的batchedUpdates批处理,当触发事件,多个this.setState,只触发一次,多次合并为一次,提升react性能。
全局变量executionContext |= BatchedContext
setTimeOut, 全部的上下文不存在BathedContext,跳出,同步更新
以上是基于ReactDom.render(<App />, rootElement) legacy模式
如果开启Concurrent模式则全是异步, ReactDom.unstable_createRoot(rootElement).render(App /)

