setState
setState立马执行之后,是无法直接获取到最新的state的,需要经过React对state的所有改变进行合并处理之后,才会去计算新的虚拟dom,再根据最新的虚拟dom去重新渲染真实dom。
1 |
|
结果
1 | console: 0 |
React 其实会维护着一个 state 的更新队列,每次调用 setState 都会先把当前修改的 state 推进这个队列,在最后,React 会对这个队列进行合并处理,然后去执行回调。根据最终的合并结果再去走下面的流程(更新虚拟dom,触发渲染)。
setState为什么要设计成“异步”的,因为setState()
之后无法立马获取最新的 state,给人的感觉便是异步去设置状态。也确实是有异步的感觉。
合成事件
React为了解决跨平台,兼容性问题,自己封装了一套事件机制,代替了原生的事件,像在jsx中常见的onClick、onChange这些都是合成事件
原生事件
原生事件是指非React合成事件,原生自带的事件监听addEventListener,或者也可以用原生js,jquery直接document.querySelector().onclick 这种绑定事件的形式都属于原生事件。
点击执行,点一点理解就很清楚了
1 | class App extends Component { |
结论
下面的异步是带引号的
- setState 只在合成事件和钩子函数中的是异步的,在原生事件和setTimeout中都是同步的
- setState 的异步并不是说内部由异步代码实现,其实本身执行的过程中和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,形成了所谓的异步,当然可以通过第二个参数setState(partialState, callback)中的callback拿到更新后的结果
- setState 的批量更新优化也是建立在异步(合成事件,钩子函数)只上的,在原生事件和setTimeout中不会批量更新,在异步中如果对同一个值进行多次setTimeout,setState的批量更新策略会对其进行覆盖,取最后一次的执行,如果是同事setState对个不同的值,在更新时会对其进行合并批量更新
20210107补充
setState 异步的,性能优化过程中的batchedUpdates批处理,当触发事件,多个this.setState,只触发一次,多次合并为一次,提升react性能。
全局变量executionContext |= BatchedContext
setTimeOut, 全部的上下文不存在BathedContext,跳出,同步更新
以上是基于ReactDom.render(
如果开启Concurrent模式则全是异步, ReactDom.unstable_createRoot(rootElement).render(App /)