setState 和批处理
batchingStrategy 对象可以理解为“锁管理器”。
这里的“锁”,是指 React 全局唯一的 isBatchingUpdates 变量,isBatchingUpdates 的初始值是 false,意味着“当前并未进行任何批量更新操作”。每当 React 调用 batchedUpdate 去执行更新动作时,会先把这个锁给“锁上”(置为 true),表明“现在正处于批量更新过程中”。
当锁被“锁上”的时候,任何需要更新的组件都只能暂时进入 dirtyComponents 里排队等候下一次的批量更新,而不能随意“插队”。此处体现的“任务锁”的思想,是 React 面对大量状态仍然能够实现有序分批处理的基石。
React 中 setState 后发生了什么
在代码中调用 setState 函数之后,React 会将传入的参数对象与组件当前的状态合并,然后触发调和过程(Reconciliation)。经过调和过程,React 会以相对高效的方式根据新的状态构建 React 元素树并且着手重新渲染整个 UI 界面。
在 React 得到元素树之后,React 会自动计算出新的树与老树的节点差异 diff,然后根据差异对界面进行最小化重渲染。在差异计算算法中,React 能够相对精确地知道哪些位置发生了改变以及应该如何改变,这就保证了按需更新,而不是全部重新渲染。
如果在短时间内频繁 setState。React 会将 state 的改变压入栈中,在合适的时机,批量更新 state 和视图,达到提高性能的效果。
出于性能原因,会将 React 事件处理程序中的多次 React 事件处理程序中的多次 setState 的状态修改合并成一次状态修改。 最终更新只产生一次组件及其子组件的重新渲染
React 将一次渲染分为两个阶段:Reconciler, commit,具体来说:
-
Reconciler 阶段(可以打断) setState 创建一个 update,将 Update 对象入队到 updateQueue 中 Scheduler 查看是否有更高优先级的任务,并将创建的更新加入任务队列,等待调度 在 requestIdleCallback 空闲时执行任务 从根节点开始遍历 FiberNode,并且构建 WorkInProgress Tree (用于处理 FiberNode 中间状态) Reconciler(协调器) 阶段生成 EffectList(用于纪录副作用,比如 DOM 更新,生命周期方法等)
-
Commit 阶段(不可打断) Renderer 根据 effectList 对 DOM 进行实际更新