从源码深度解析 React:Hook 如何在 Fiber 中存储?DOM Ref 如何绑定?

深入 Fiber 内部:Hook 链表结构与 DOM Ref 绑定的奥秘

前言

在前两篇文章中,我们从业务实战角度解决了重复请求和高频并发拦截的问题。我们学到了 useRef 是同步的物理锁,而 useState 是异步的状态快照。然而,作为一个进阶开发者,我们不能止步于"怎么用",更要探究"为什么"。

React 是如何在内存中记住这些 Hook 的?为什么 Hook 必须遵守不能在条件语句中使用的"死律"?<div ref={myRef}> 又是如何在毫秒之间精准捅到真实 DOM 上的?本文将带你潜入 React Fiber 架构的底层,拆解这些核心机制。


1. Hook 的持久化存储:单向链表结构

在 React 内部,每一个函数组件都对应一个 Fiber 对象。Fiber 是 React 更新过程中的最小工作单元,它在内存中持久化存储了组件的所有元数据。

Hook 对象的"串葫芦"模型

当你连续调用多个 Hook 时,React 并不是按名称存储的,而是将它们拼成了一个有序的单向链表

  • Fiber.memoizedState :在函数组件中,它并不直接存值,而是指向这个链表的表头(即第一个 Hook 对象)。
  • Hook.next:每个 Hook 对象内部都有一个指针,指向下一个 Hook。

为什么 Hook 不能写在 if 语句中?

因为 React 查找 Hook 的唯一证据是执行顺序 。如果第二渲染时某个 if 导致少了一个 Hook 调用,整个链表的顺序就会错位,React 会把原本属于索引 3 的状态强行套在索引 2 上,导致内存数据彻底混乱。


2. 核心概念辨析:两个 memoizedState

在查阅底层原理时,经常会看到两个同名的属性,必须严加区分:

  1. Fiber.memoizedState

    • 角色:链表管理员。
    • 存储内容:指向整个 Hook 链表的第一个节点。
  2. Hook.memoizedState

    • 角色:数据存储员。
    • 存储内容:该 Hook 对应的具体数据。
    • 注意 :对于 useState,这里存的是状态值;对于 useRef,这里存的是对象 { current: ... }

3. 渲染的两阶段:从"画稿"到"施工"

理解调度逻辑的关键在于区分 React 的两个核心运行阶段:

阶段 A:渲染阶段 (Render Phase)

  • 核心动作:计算差异(Diffing)。
  • 特点 :纯计算,不操作 DOM
  • 状态流转
    1. 调用函数组件。
    2. 遇到 useState,去 Hook.queue 里看有没有未处理的更新任务。
    3. 计算出新值,并作为渲染快照返回。
      此时,如果你直接通过 Ref 访问 DOM,你会发现它是 null 或旧的,因为"施工队"还没进场。

阶段 B:提交阶段 (Commit Phase)

  • 核心动作:将计算结果应用到真实浏览器视图。
  • 关键细节 :这是一个同步且不可中断的过程,分为三个子阶段:
    1. Before Mutation:准备工作。
    2. Mutation :真正的 DOM API 调用(如 appendChild)。
    3. Layout :此时 DOM 已经挂载。这是 Ref 赋值的发生时刻。

4. Ref 绑定 DOM 的内部链路

当你写下 <div ref={myRef}> 时,内部经历了如下逻辑:

  1. 标记阶段 (Render) :React 在构建虚拟 DOM 时,发现该元素携带了 ref 属性,会在对应的 Fiber 节点上打一个名为 Ref 的标志位(Flags)。
  2. 赋值阶段 (Commit)
    • 当施工队(Commit 流程)完成 DOM 节点的创建后,会检查标志位。
    • React 内部通过类似于 fiber.ref.current = fiber.stateNode 的操作,强行将真实的 DOM 元素地址写入你提供的 useRef 对象中。
  3. 通知阶段 :随后触发 useEffectuseLayoutEffect 回调,此时开发者可以安全地操作 DOM。

5. 总结:第一性原理的终点

通过这三篇文章的探索,我们终于摸清了 React 状态管理的底层逻辑:

  • 稳定性源于顺序:Hook 的链表结构决定了调用的顺序不可动摇。
  • 更新源于计算useState 的异步源于它需要经历 Render 到 Commit 的完整闭环计算。
  • Ref 是后门useRef 既是绕过渲染周期的同步变量,又是 React 在 Commit 阶段留给开发者的 DOM 访问接口。

掌握了 Fiber 内部的"串葫芦"模型和两阶段提交机制,你将不仅能修复表面的 Bug,更能在架构设计时预判数据的流向与风险。这就是从业务开发迈向技术专家的核心内功。

相关推荐
saber_andlibert6 分钟前
TCMalloc底层实现
java·前端·网络
逍遥德7 分钟前
如何学编程之01.理论篇.如何通过阅读代码来提高自己的编程能力?
前端·后端·程序人生·重构·软件构建·代码规范
冻感糕人~21 分钟前
【珍藏必备】ReAct框架实战指南:从零开始构建AI智能体,让大模型学会思考与行动
java·前端·人工智能·react.js·大模型·就业·大模型学习
程序员agions25 分钟前
2026年,“配置工程师“终于死绝了
前端·程序人生
alice--小文子31 分钟前
cursor-mcp工具使用
java·服务器·前端
晚霞的不甘40 分钟前
揭秘 CANN 内存管理:如何让大模型在小设备上“轻装上阵”?
前端·数据库·经验分享·flutter·3d
小迷糊的学习记录1 小时前
0.1 + 0.2 不等于 0.3
前端·javascript·面试
梦帮科技1 小时前
Node.js配置生成器CLI工具开发实战
前端·人工智能·windows·前端框架·node.js·json
VT.馒头2 小时前
【力扣】2695. 包装数组
前端·javascript·算法·leetcode·职场和发展·typescript
css趣多多2 小时前
一个UI内置组件el-scrollbar
前端·javascript·vue.js