生命周期和 Fiber 架构
一、 React 组件的生命周期
React 类组件的生命周期可分为 挂载阶段(Mounting)、更新阶段(Updating)、卸载阶段(Unmounting),以及 React 16.3+ 新增的错误处理阶段(Error Handling)。
1. 挂载阶段(组件首次渲染到 DOM)
constructor():构造函数,初始化state或绑定事件处理函数(必须调用super(props))static getDerivedStateFromProps(props, state)(React 16.3 +):静态方法,在组件创建或更新前根据props更新state(返回需合并的state对象或是null)render():返回 JSX 描述的 UI 结构(纯函数,不修改状态或 DOM)componentDidMount():组件挂载后调用(DOM 已存在),适合执行副作用(如数据请求、定时器)
2. 更新阶段(setState 或父组件重新渲染触发)
static getDerivedStateFromProps(props , state):同上,在更新前触发shouldComponentUpdate(nextProps, nextState):返回布尔值,决定是否跳过更新(优化性能,比较props/state变化)render():重新生成 UI 描述getSnapshotBeforeUpdate(prevProps, prevState)(React 16.3+):在 DOM 更新前捕获快照(如滚动位置),返回值传递给componentDidUpdatecomponentDidUpdate(prevProps, prevState, snapshot):DOM 更新后调用(可执行副作用,如根据新的 props 重新请求数据)
3. 卸载阶段(组件从 DOM 树移除)
componentWillUnmount():组件卸载前调用(清理定时器、取消网络请求、移除监听事件)
4. 错误处理阶段(子组件渲染出错时)
static getDerivedStateFromError(error):静态方法,捕获子组件错误并更新state(返回需合并的state)componentDidCatch(error, info):记录错误信息(如上报日志)
React 16.3+ 后废弃了 componentWillMount、componentWillReceiveProps、componentWillUpdate (标记为 UNSAFE_ 前缀,推荐使用更安全的生命周期或 getDerivedStateFromProps 代替。
二、 React Fiber 架构
React Fiber 是 React 16+ 引入的协调引擎,代替了旧的栈调和(stack reconciler)。其核心目标是将不可中断的长任务拆分为可中断的增量任务,提升应用响应速度。
Fiber 架构的核心结构:Fiber 节点
每个元素对应一个 Fiber 节点,储存组件的类型、状态(state/props)、副作用(如 DOM 更新)、子节点/兄弟节点等信息。Fiber 树(工作进度树)通过链表结构连接所有的 Fiber 节点,支持增量遍历。
与旧的树形递归结构不同,Fiber 将组件树构建成一个链表。每个 Fiber 通过 return (执行父节点)、child (指向第一个子节点)、sibling(执行下一个兄弟节点)指针连接起来。这种结构使得 React 可以 增量地遍历树,而不是一次性递归到底。
Fiver 架构图关键流程:
- 协调阶段
- 提交阶段
- 调度器
1. 协调阶段(Reconciliation,可中断)
- 遍历组件树,对比新旧
props/state,标记需要更新的 Fiver 节点(产生副作用) - 使用
requestIdleCallback或requestAnimationFrame拆分任务,每完成一个 Fiber 节点检测是否有更高优先级任务(如用户输入),若有则打断当前任务,保留进度后继续
2. 提交阶段(Commit ,不可中断)
- 将协调阶段标记的副作用一次性更新到 DOM (如更新元素、调用生命周期)
- 此阶段必须同步执行,确保 DOM 更新的一致性
3. 调度器
- 管理任务列表,根据优先级决定执行顺序
- 使用
requestIdleCallback或MessageChannel实现任务分片
三、 Fiber 解决的核心问题
1. 可中断更新(Incremental Rendering)
旧版栈调和(Stack Reconciler)使用递归遍历组件树,一旦开始无法中断。若组件庞大,长任务会阻塞主线程,导致页面卡顿(如输入延迟、动画掉帧)。
Fiber 通过将任务拆分为微任务单元(每个 Fiber 节点为一个单元),利用浏览器的空余时间(requestIdleCallback)或时间切片(requestAnimationFrame)执行。每完成一个单元,检测是否有更高级优先级的任务(如用户交互),若有则暂停当前任务并保存进度(通过 Fiber 节点的链表结构记录当前处理位置),后续恢复时执行。
2.优先级调度(Priority Scheduling)
Fiber 为不同类型的更新分配了优先级(如用户输入事件 > 数据加载 > 列表渲染)。高优先级任务可中断第优先级的任务,确保关键操作(如按钮点击)快速响应。
- Immediate:用户输入、错误处理,立即执行
- UserBlocking:动画、点击状态变化,尽快执行
- Normal:数据请求后的列表渲染,可中断
- Low/Idle:非关键日志、延迟加载,低优先级执行
四、双缓存树(Double Buffering)
Fiber 使用双缓存技术管理 Fiber 树,解决“如何高效生成下一帧 UI”的问题。
1. 双缓存树的定义
- 当前树(
Current Tree):对应当前屏幕显示的 UI,已完成提交状态 - 工作进度树(
WorkInProgress Tree):正在协调阶段构建的下一帧 UI 树
2. 工作流程
- 初始时,
current tree指向当前树 - 当需要更新时,基于
current tree的 Fiber 节点克隆生成workInProgress tree(浅拷贝,复用大部分节点) - 协调阶段修改
workInProgress tree的属性(如更新state),标记副作用 - 提交阶段完成后,
workInprogress tree变成新的current tree(通过指针交换),旧current tree变成为下一次的workInProgress tree(节点被复用)
3. 优势
- 减少内存开销:复用 Fiber 节点,避免频繁创建/销毁对象
- 可中断:如果构建过程被打断,可以安全地丢弃
WorkInprogress Tree - 高效切换:通过指针交换快速完成切换,无需重新构建整棵树
五、为什么需要 Fiber
根本原因是前端应用的复杂度提升,旧版栈调和无法满足性能条件:
- 长时间阻塞主线程:栈调和的递归特性导致无法中断,复杂组件树可能会导致页面的卡断(如滚动时延迟输入)
- 缺乏优先级控制:所有的更新按顺序执行,低优先级任务(如列表渲染)可能阻塞高优先级任务(如用户点击)
- 无法感知任务耗时:无法统计单个组件的渲染时间,难以针对性优化
Fiber 通过以下方式解决:
- 可中断的增量渲染:将长任务拆分为微任务,避免阻塞主线程
- 优先级调度:确保关键任务优先执行,提升用户体验
- 双缓存树:高效生成下一帧 UI,减少内存和计算开销
且 Fiber 支持
- 并发特性:为
Suspense、Time Slicing等特性提供底层支持,例如异步加载组件时保持洁面响应 - 错误边界和调试:
- 每个 Fiber 节点可捕获子树错误,避免整个应用奔溃
- 支持时间旅行,优化开发者工具体验