前言
在 React 中,理解 React 整个运作流程非常重要。
在 React 中,我们写的组件会经历从 组件实例 通过 React.createElement() 创建 React组件,DOM 组件(HTML),最终呈现到用户的屏幕上。可是在React组件 到最终呈现在用户的屏幕上,这期间的整个流程是怎么样的?
这其中的整个运作的流程可以分成四个步骤:
- 触发
- 渲染阶段(Render Phase)
- 提交阶段(Commit Phase)
- 浏览器绘制
触发
触发的条件:
- 整个应用程序的 初始渲染
- 一个或者多个组件的状态发生改变(我们又称为 重新渲染)
👉 渲染并不是立刻生效的! 当你调用 setState 方法时,React 并不会立即重新渲染组件。相反,React 会将渲染操作调度到 JavaScript 引擎有空闲时间的时候执行。这种机制可以避免频繁的渲染操作,从而提高性能。
渲染阶段(Render Phase)
- 遍历组件树,获取其所有的需要被重新渲染的组件并渲染他们。
- 会根据 React 元素生成树,这个树通常被称为是
虚拟DOM(如图所示)。
- 如果有一个子元素状态变化时,该元素的所有子元素都会被重新渲染(无论子元素有没有改变过)。
- 状态更新后的
虚拟DOM树将与当前的Fiber树保持协调一致,会更新成一个新的Fiber树。
Fiber 树
在渲染阶段提到了 Fiber 树,为什么我们需要 Fiber 树,而不是在状态改变的时候直接更新 DOM 树呢?
当然是因为直接操作 DOM 树 贵 并且 慢 。通过 Fiber 树,我们可以只更新虚拟DOM的一小部分,不需要改动的部分可以进行复用。
Fiber 树的运作
通过 React 元素树(也就是虚拟DOM),在初始渲染的时候创建 Fiber 树。因为 Fiber 树的特性(可变的数据结构),在一开始被创建的时候,Fiber 树就不会被摧毁,同时经历重新渲染也不会重新创建一棵新的 Fiber 树。
因此,Fiber 树也被用于跟踪各个组件的状态(使用过的hooks,props,当前状态,effects等)。他们都会被存储在 Fiber 的内部。
Fiber 树的结构虚拟 DOM 有着差异,Fiber 树采用链表的结构,而每一个节点也被称为 Fiber。
Fiber 树的优势
-
增量渲染:Fiber 允许 React 将渲染工作拆分成多个小任务,从而可以在主线程空闲时执行这些任务,提高渲染性能。
-
可中断的渲染:由于渲染工作被拆分成了小任务,React 可以在任务之间中断渲染,以便处理更高优先级的任务(如用户交互)。
-
优先级调度:Fiber 支持为不同的更新任务分配不同的优先级,使得 React 能够优先处理重要的更新。
渲染阶段的流程图
提交阶段(Commit Phase)
在提交阶段,是由
ReactDOM完成的(不是React)
👉 React 写入 DOM:插入、删除和更新(DOM 更新列表被“刷新”到 DOM 中)
👉 提交是同步的:DOM 更新一次性完成,不能被中断。这是必要的,以确保 DOM 不会显示部分结果,始终与状态保持一致
👉 提交阶段完成后,workInProgress Fiber 树将成为下一次渲染周期的 current 树。
浏览器绘制
通过提交阶段的提交,浏览器(或者是移动端等),通过提交对页面进行绘制。
总结
我们可以发现,React 总是不参与跟真实 DOM 的交互,总是在虚拟 DOM 上进行操作。这使得 React对于性能有较好的优化。
最后总结了一份流程图: