跳到主要内容

生命周期和 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 更新前捕获快照(如滚动位置),返回值传递给 componentDidUpdate
  • componentDidUpdate(prevProps, prevState, snapshot):DOM 更新后调用(可执行副作用,如根据新的 props 重新请求数据)

3. 卸载阶段(组件从 DOM 树移除)

  • componentWillUnmount():组件卸载前调用(清理定时器、取消网络请求、移除监听事件)

4. 错误处理阶段(子组件渲染出错时)

  • static getDerivedStateFromError(error):静态方法,捕获子组件错误并更新 state(返回需合并的 state
  • componentDidCatch(error, info):记录错误信息(如上报日志)
注意

React 16.3+ 后废弃了 componentWillMountcomponentWillReceivePropscomponentWillUpdate (标记为 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 节点(产生副作用)
  • 使用 requestIdleCallbackrequestAnimationFrame 拆分任务,每完成一个 Fiber 节点检测是否有更高优先级任务(如用户输入),若有则打断当前任务,保留进度后继续

2. 提交阶段(Commit ,不可中断)

  • 将协调阶段标记的副作用一次性更新到 DOM (如更新元素、调用生命周期)
  • 此阶段必须同步执行,确保 DOM 更新的一致性

3. 调度器

  • 管理任务列表,根据优先级决定执行顺序
  • 使用 requestIdleCallbackMessageChannel 实现任务分片

三、 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 支持

  • 并发特性:为 SuspenseTime Slicing 等特性提供底层支持,例如异步加载组件时保持洁面响应
  • 错误边界和调试:
    • 每个 Fiber 节点可捕获子树错误,避免整个应用奔溃
    • 支持时间旅行,优化开发者工具体验