React 执行阶段与渲染机制详解(基于 React 18+ 官方文档)

React 执行阶段与渲染机制详解(基于 React 18+ 官方文档)

🌟 核心概念:React 的执行流程分层

React 的工作流程基于 Fiber 架构 ,将任务拆分为可中断的单元,核心分为 Render Phase(渲染阶段)Commit Phase(提交阶段) ,并辅以 副作用阶段卸载阶段。以下是详细解析:


一、Render Phase(渲染阶段 / 协调阶段)

1. 作用与触发

  • 目的:计算新的 Virtual DOM 树,并与旧树进行 Diff(协调算法),决定需要更新的部分。
  • 触发条件
    • 初始挂载(Mount)
    • 状态更新(State Update):useState/useReducer
    • Props 变化(父组件重渲染)
    • 强制更新(forceUpdate

2. 特性

  • 纯函数性 :组件函数必须是纯函数,禁止修改外部状态或变量 (如 propsstate、全局变量)。
  • 可中断性:React 18 的并发模式下,此阶段可被中断或重启,优先处理高优先级任务。
  • Strict Mode 行为 :开发环境下,React 会双调用组件函数,用于检测非纯函数导致的副作用。

3. 代码示例

jsx 复制代码
function Counter({ time }) {
  // 纯函数:相同输入返回相同 JSX
  return (
    <>
      <h1>{time}</h1>
      <input /> {/* 用户输入不会因父组件重渲染而丢失 */}
    </>
  );
}

二、Commit Phase(提交阶段)

1. 作用

将 Render Phase 计算出的变更同步应用到真实 DOM,确保用户界面即时更新。

2. 三个子阶段

  1. Before Mutation
    • 执行 getSnapshotBeforeUpdate(类组件)
    • 执行 useLayoutEffect清理函数
  2. Mutation
    • 实际插入、更新、删除 DOM 节点
  3. Layout
    • 执行 useLayoutEffect创建函数
    • 类组件的 componentDidMount/componentDidUpdate

3. 关键特性

  • 不可中断:此阶段必须一次性完成,确保 DOM 操作的原子性。
  • 避免闪烁 :React 仅更新差异节点(Diff 结果),保证 input 值等用户交互状态不丢失。

三、Passive Effect Phase(被动副作用阶段)

1. 作用

在浏览器完成布局和绘制后,异步执行副作用(如网络请求、订阅)。

2. 执行内容

  • useEffect 的创建函数和清理函数
  • 类组件的 componentDidMount/componentDidUpdate/componentWillUnmount 中的异步操作

3. 与 useLayoutEffect 的区别

Hook 执行时机 是否阻塞渲染 适用场景
useEffect Passive Phase ❌ 否 数据获取、日志、非关键副作用
useLayoutEffect Commit Phase(Layout 阶段) ✅ 是 同步 DOM 操作(如测量尺寸)

四、Unmount Phase(卸载阶段)

1. 触发条件

组件从 DOM 中移除(如条件渲染切换、列表项删除)。

2. 执行内容

  • 清理 useEffect/useLayoutEffect 的副作用
  • 类组件的 componentWillUnmount

五、状态保留与重置机制

1. 状态隔离规则

  • 相同位置保留状态 :组件在树中的位置不变时,React 保留其 state
  • 位置变化重置状态:组件位置变化时,React 会销毁旧组件并初始化新组件(即使类型相同)。

2. 控制状态保留的技巧

  • Key 属性 :通过唯一 key 标识列表项,避免位置变化导致的状态重置。
  • 条件渲染:动态切换组件类型时,状态会被重置(即使 props 相同)。
jsx 复制代码
function App() {
  const [isFancy, setIsFancy] = useState(false);
  return (
    <div>
      {isFancy ? <Counter isFancy={true} /> : <Counter isFancy={false} />}
    </div>
  );
}

上述示例中,<Counter /> 的位置不变,因此 score 状态会保留。


六、错误处理机制(Error Boundaries)

1. 执行阶段

  • getDerivedStateFromError:同步执行,用于渲染降级 UI。
  • componentDidCatch:提交阶段执行,用于记录错误日志。

2. 限制

  • 无法捕获的错误 :事件处理器、异步代码(如 setTimeout)、服务端渲染(SSR)中的错误。

七、性能优化策略

1. 避免过早优化

  • 默认行为:React 的 Diff 算法已足够高效,优先保证代码可读性。
  • 优化时机 :当性能瓶颈明显时,使用 React.memouseMemouseCallback 等工具。

2. 优化技巧

  • 减少不必要的 re-renders :使用 React.memo 包裹子组件。
  • 避免在 Render Phase 创建对象/函数 :使用 useMemo/useCallback 缓存。
  • 并发模式下的优先级调度:React 自动优化任务优先级,无需手动干预。

八、官方文档与术语参考


九、总结:React 执行流程全貌

csharp 复制代码
用户交互 / 状态更新
        ↓
   [Render Phase](协调)
        ↓
   [Commit Phase]
   ├── Before Mutation → useInsertionEffect / getSnapshotBeforeUpdate
   ├── Mutation        → DOM 更新
   └── Layout          → useLayoutEffect / componentDidMount/Update
        ↓
[Passive Effect Phase] → useEffect
        ↓
[Unmount Phase] → 清理副作用

掌握这一流程,能帮助你编写更符合 React 设计哲学的代码,避免常见陷阱(如非纯函数、滥用 useLayoutEffect),并充分利用 React 的并发能力提升应用性能。

相关推荐
jump_jump1 天前
超长定时器 long-timeout
前端·javascript·node.js
Mintopia1 天前
架构进阶 🏗 从 CRUD 升级到“大工程师视野”
前端·javascript·全栈
Mintopia1 天前
小样本学习在 WebAI 场景中的技术应用与局限
前端·人工智能·aigc
光影少年1 天前
vue生态都有哪些?
前端·javascript·vue.js
一只大头猿1 天前
基于SpringBoot和Vue的超市管理系统
前端·vue.js·spring boot
用户1456775610371 天前
告别繁琐操作!Excel合并原来可以这么轻松
前端
itslife1 天前
vite 源码 - 创建 ws 服务
前端·javascript
懒人Ethan1 天前
解决一个C# 在Framework 4.5反序列化的问题
java·前端·c#
用户1456775610371 天前
Excel合并数据太麻烦?这个神器3秒搞定,打工人必备!
前端
西洼工作室1 天前
前端混入与组合实战指南
前端