#协调器
Review
- 2024-09-30 11:28
[!Summary] Reconciler 工作的阶段在 React 内部被称为
render phase。根据Scheduler调度的结果,执行performSyncWorkOnRootorperformConcurrentWorkOnRootReconciler 支持异步可中断
一、Introduction #
功能 #
- 输入:提供 API (
sheduleUpdateOnFiber) 给外界调用 - 注册Scheduler:与 Scheduler 交互,注册调度任务 (
ensureRootIsScheduled) - 执行回调:执行
performSyncWorkOnRootorperformConcurrentWorkOnRoot,构造 FiberTree,创建新的FiberTree,提交(commitRoot)给 Renderer - 输出:Renderer(
react-dom,react-native) 渲染页面
流程 #
Rendering #
- On initial render, React will call the root component.
- For subsequent renders, React will call the function component whose state update triggered the render.
Reconciler 的流程,采用 DFS 的顺序构建 workInProgress Fiber Tree,整个过程分为“递”与“归”两个阶段,分别对应 beginWork 和 completeWork 方法。
beginWork 会根据当前 fiberNode 创建下一级 fiberNode,在 update 阶段标记 Placement(新增、移动),ChildDeletion(删除)。
completeWork 在 mount 阶段会构建 Fiber Tree,初始化属性,在 update 时标记 Update(属性更新),最终执行 flags 冒泡。
当最终 HostRootFiber 完成 completeWork 时,Reconciler的工作流程结束。
此时得到的结果是
- 代表本次更新的 wip fiber tree
- 被标记的 flags
Rendering 阶段可以被暂停,通过调用下面的方法/组件
SuspenseuseTransition->startTransition
eagerState 策略 #
当一个组件的状态发生变化时,React 通常会重新渲染该组件及其子组件。然而,如果新状态与旧状态相同,那么重新渲染就是没有必要的。eagerState 就是为了解决这个问题而诞生的。
- 提前计算下一个状态: 在某些特定情况下,React 可以提前计算出下一个状态,并将其与当前状态进行比较。
- 避免不必要的渲染: 如果新旧状态相同,那么 React 就可以跳过该组件的渲染过程,从而提高性能。
触发条件 #
- 当前组件没有其他更新: 也就是说,当前组件的更新队列中只有这一次状态更新。
- 更新队列中只有一个更新: 如果有多个更新,那么无法确定最终的状态,也就无法提前计算。
Bailout 策略 #
Reconciler 阶段执行
命中 Bailout 策略,可以复用子 FiberNode,可以跳过子树的 beginWork。eagerState 算是一种 Bailout 的优化方式。
满足条件
- oldProps === newProps
- Legacy Context (old Context API) 没有变化
- fiberNode.type 没有变化
- 当前 fiberNode 没有更新发生
相关性能优化API
React.memo()- shouldComponentUpdate
- PureComponent
reconciliation #
执行 beginWork ,进入
mountChildFibersorreconcileChildFibers
reconcile 流程的本质,是对比 current fiberNode 与 JSX 对象,生成 workInProgress fiberNode。
对比算法(diffing algorithm)规则
- 只对同级元素进行Diff
- 两个不同类型的元素会产生不同的树
- 开发者可以通过 key 来暗示子元素在不同的渲染下能够保持稳定
Diff算法可细分为
- 单节点 diff
- 多节点 diff
单节点 diff 需要考虑
- 节点复用问题
- 多余节点删除
多节点 diff 需要考虑
- 节点复用问题
- 节点的增删
- 节点的移动