这是个很核心的问题,让我画一张图来说清楚三者的关系。下面把三者关系说清楚:

虚拟 DOM(React Element)
JSX 经 Babel 编译成 React.createElement(...) 调用,返回的就是虚拟 DOM —— 一个普通 JS 对象 { type, props, key, ref }。它只描述”应该渲染什么” ,非常轻量,每次 render 都会重新生成。它本身不持有真实 DOM 引用、不知道副作用、不知道调度优先级。
Fiber 节点和 Fiber 树
Fiber 节点是虚拟 DOM 的”升级版”,除了描述信息外,还额外存储了:
- 对应的真实 DOM 引用(
stateNode) - 副作用标记(
flags) - 调度优先级(
lanes) - 钩子链表(
memoizedState) - 指向父/子/兄弟节点的指针
谁创建了 Fiber 节点? 在 reconciler 的 render phase,React 以虚拟 DOM 为输入,调用 createFiber 或 createWorkInProgress 创建 Fiber 节点,组装成树。
current 树 vs workInProgress 树
这是 React 的双缓冲机制:
- current 树:对应屏幕上当前显示的状态,
FiberRoot.current指向它的根节点 - workInProgress(wip)树:本次更新正在构建的”草稿”,render phase 全程操作它
- 两棵树中对应的节点通过
.alternate属性互相引用
关键时序:
- 触发更新 → render phase 开始,以虚拟 DOM 为输入,基于 current 树创建/复用节点,构建 wip 树
- wip 树构建完成,进入 commit phase
- commit phase 结束 →
FiberRoot.current = wip,完成指针交换 - 原来的 current 树此刻变成”空闲”状态,下次更新时作为 wip 复用的节点池
这样的好处是:render phase 可以被中断(操作的是 wip,不影响屏幕),commit phase 一气呵成(不可中断,直接操作真实 DOM),用户看到的始终是完整一致的 current 树。
资料来源:www.duskjoy.com