3-4 Fiber带来的Effects(效应)
什么是 Effects(副作用)
双缓存和 Fiber 树解决了任务的优先级调度和执行效率问题,但实际应用中组件还需要执行一些额外的操作——比如网络请求、DOM 操作、生命周期方法的调用。这些操作在 React 中被称为 Effects(副作用)。
副作用的本质就是:React 在渲染过程中记录哪些节点需要插入、修改、删除,以及哪些生命周期方法需要执行。
副作用与 React 核心设计思想中的"代数效应(Algebraic Effects)"一脉相承——将跨层级的逻辑(如生命周期、DOM 操作)从组件树的层级传递中抽离出来,统一管理。
副作用的类型
| 副作用类型 | 说明 | 示例 |
|---|---|---|
| DOM 更新 | 插入、修改、删除 DOM 元素 | document.createElement、node.removeChild |
| 生命周期调用 | 挂载/更新阶段的钩子方法 | componentDidMount、componentDidUpdate |
| Ref 更新 | 更新 ref 引用 | ref.current = node |
副作用是高度依赖 Fiber 对象的——每个 Fiber 节点都会标记自己是否包含副作用以及副作用的类型。
副作用与两个阶段的关系
Fiber 架构将渲染分为两个阶段,副作用在这两个阶段中有不同的表现:
渲染阶段(Render Phase)—— 异步可中断
在这个阶段只执行纯计算逻辑,不产生任何用户可见的副作用:
render()方法——纯函数,返回 UI 描述shouldComponentUpdate()——决定是否需要更新- 计算 Diff,收集需要执行的副作用列表
这个阶段可以被中断、暂停和恢复,不会导致界面不一致。
提交阶段(Commit Phase)—— 同步不可中断
在这个阶段执行所有收集到的副作用:
beginWork → 拆分任务、计算 Diff
↓
Fiber 树构建完成
↓
completeWork → 通知 DOM 执行一次更新
↓
提交所有 Effects
↓
所有变更一次性呈现给用户
text
关键特性:所有副作用会在一次渲染中集中执行,不会出现部分更新、部分未更新的中间状态。
beginWork 与 completeWork
这是 Fiber 工作流程的入口和出口:
beginWork(入口):
- 接收当前 Fiber 节点
- 根据 tag 类型进行不同的处理
- 比较新旧 props,计算差异
- 创建或复用子 Fiber 节点
- 向下遍历 child
completeWork(出口):
- 当 Fiber 节点的所有子节点处理完毕
- 收集当前节点的副作用
- 创建或更新真实的 DOM 节点
- 将副作用向上冒泡到父节点
- 向上 return 到父 Fiber
beginWork(A) → beginWork(B) → beginWork(C)
↓
completeWork(C) → completeWork(B) → completeWork(A)
text
建议在阅读 React 源码时,从 beginWork 函数开始入手,它是理解 Fiber 工作流程的最佳入口点。
Fiber 架构总结
| 概念 | 作用 | 核心机制 |
|---|---|---|
| Fiber 对象 | 最小工作单元 | 包含 type、key、stateNode 等属性 |
| Fiber 树 | 任务组织结构 | child、sibling、return 建立树形关系 |
| 双缓存 | 高效渲染切换 | current 与 workInProgress 通过 alternate 连接 |
| 时间切片 | 任务调度 | requestAnimationFrame + requestIdleCallback |
| 优先级 | 任务排序 | 高优先级(动画)优先,低优先级(网络请求)延后 |
| Effects | 副作用管理 | 在提交阶段集中执行 DOM 操作和生命周期 |
Fiber 的本质是 React 内部状态更新的一种协程式调度机制——在计算机空闲时执行细小的工作单元,在高优先级任务到来时让出执行权。React 16+ 的很多重量级功能都建立在 Fiber 架构之上:
- Error Boundaries——基于 Fiber 的错误捕获机制
- Suspense——异步组件,依赖 Fiber 的可中断渲染
- Concurrent Mode——并发模式,Fiber 优先级调度的完整实现
- startTransition——标记低优先级更新的 API
理解了 Fiber 的工作原理,再看这些高级特性就会豁然开朗——它们都是 Fiber 架构能力的具体应用。
↑