react渲染流程、更新机制

608 阅读3分钟

1.初次渲染流程

流程:

  1. 根组件的 JSX 定义会被 babel 转换为 React.createElement 的调用,其返回值为 VNode树
  2. React.render 调用,实例化 FiberRootNode,并创建 根Fiber 节点 HostRoot 赋值给 FiberRoot 的 current 属性
  3. 创建更新对象,其更新内容为 React.render 接受到的第一个参数 VNode树,将更新对象添加到 HostRoot 节点的 updateQueue 中
  4. 处理更新队列,从 HostRoot 节点开始遍历,在其 alternate 属性中构建 WIP 树,在构建 Fiber 树的过程中会根据 VNode 的类型进行组件实例化、生命周期调用等工作,对需要操作视图的动作将其保存到 Fiber 节点的 effectTag 上面,将需要更新在DOM上的属性保存至 updateQueue 中,并将其与父节点的 lastEffect 连接。
  5. 当整颗树遍历完成后,进入 commit 阶段,此阶段就是将 effectList 收集的 DOM 操作应用到屏幕上。
  6. commit 完成将 current 替换为 WIP 树。

preview

2.更新渲染流程

图见上。

流程:

  1. 组件调用 setState 触发更新,React 通过 this 找到组件对应的 Fiber 对象,使用 setState 的参数创建更新对象,并将其添加进 Fiber 的更新队列中,然后开启调度流程。

  2. 从根 Fiber 节点开始构建 WIP 树,此时会重点处理新旧节点的差异点,并尽可能复用旧的 Fiber 节点。

  3. 处理 Fiber 节点,检查 Fiber 节点的更新队列是否有值,context 是否有变化,如果没有则跳过。

  4. 处理更新队列,拿到最新的 state,调用 shouldComponentUpdate 判断是否需要更新。

  5. 调用 render 方法获取 VNode,进行 diff 算法,标记 effectTag,收集到 effectList 中。

    • 对于新元素,标记插入 Placement
    • 旧 DOM 元素,判断属性是否发生变化,标记 Update
    • 对于删除的元素,标记删除 Deletion
  6. 遍历处理 effectList,调用生命周期并更新 DOM

3.更新机制

众所周知,react的setState机制是“批量更新”和“异步执行”的。其中,“批量更新”是因,“异步执行”是果。

setState和 useState 只在合成事件和react生命周期(钩子函数)中是“异步”的,在原生事件和 setTimeoutPromise.resolve().then 中都是同步的。

1.  react合成事件,如onClick等
2. react生命周期(钩子函数)包括componentDidMount、useEffect等等。

更新流程如下: setstate更新流程

执行过程:

1.将setState传入的partialState参数存储在当前组件实例的state暂存队列中。
2.判断当前React是否处于批量更新状态,如果是,将当前组件加入待更新的组件队列中。
3.如果未处于批量更新状态,将批量更新状态标识设置为true,用事务再次调用前一步方法,保证当前组件加入到了待更新组件队列中。
4.调用事务的waper方法,遍历待更新组件队列依次执行更新。
5.执行生命周期componentWillReceiveProps
6.将组件的state暂存队列中的state进行合并,获得最终要更新的state对象,并将队列置为空。 7.执行生命周期componentShouldUpdate,根据返回值判断是否要继续更新。
8.执行生命周期componentWillUpdate
9.执行真正的更新,render
10.执行生命周期componentDidUpdate

参考文档: zhuanlan.zhihu.com/p/370183031 segmentfault.com/a/119000001… juejin.cn/post/684490…