外观
React Fiber 是什么?
Fiber 是 React 的工作单元。每个组件实例对应一个 Fiber 节点。渲染被拆成很多小段,高优先级更新(例如输入)可以打断低优先级更新,最后一次性地把结果提交到 DOM。
原理
Fiber 节点之间用 child、sibling、return 连成树,方便暂停后从中间继续。同时存在两棵树:屏幕上的 current,以及正在算的 workInProgress。算完后两者互换,这是双缓冲。
更新分成两个阶段:
- 渲染阶段可以打断。React 根据类型和
key决定复用、移动还是卸载,并算出这份 Fiber 上的状态。这个阶段不改 DOM,算到一半丢掉也安全。 - 提交阶段同步执行。这里才插入、更新、删除 DOM,然后跑
useLayoutEffect。提交不能做一半,否则屏幕上会是不完整的界面。useEffect在绘制之后异步执行。
优先级用 lane 表示。点击、输入这类离散事件优先;startTransition 里的更新优先级低,可以被新的输入打断。useDeferredValue 让一份派生值停留在旧数据上,等紧急更新画完再跟上。
setState 是往调度器里放一个更新,不是当场把整棵树算完。React 18 的并发特性建立在「渲染阶段可以重来」之上。
追问
和虚拟 DOM diff 是什么关系?
diff 是比较策略:同层、看类型和 key。Fiber 是执行这套策略的数据结构,并加上了可中断的调度。见 虚拟 DOM。
为什么提交阶段不能中断?
渲染阶段只产生计算,用户看不见。提交阶段在改真实 DOM。中断会让界面停在旧节点和新节点混在一起的状态。
易错点
- Fiber 不是「新的虚拟 DOM 库」,虚拟 DOM 仍然是那棵描述 UI 的树。
- 渲染阶段可能执行多次,所以渲染期间的函数必须能重入,不要在渲染函数里发请求或改外部变量。副作用放进 effect。
startTransition不会取消更新,它只是让这次更新可以被打断、稍后再画。