从源码深度解析 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,更能在架构设计时预判数据的流向与风险。这就是从业务开发迈向技术专家的核心内功。

相关推荐
weixin_408099675 分钟前
【完整教程】天诺脚本如何调用 OCR 文字识别 API?自动识别屏幕文字实战(附代码)
前端·人工智能·后端·ocr·api·天诺脚本·自动识别文字脚本
吴声子夜歌6 分钟前
ES6——Generator函数详解
前端·javascript·es6
吴声子夜歌8 分钟前
ES6——Set和Map详解
前端·javascript·es6
码喽7号38 分钟前
vue学习四:Axios网络请求
前端·vue.js·学习
粥里有勺糖1 小时前
视野修炼-技术周刊第129期 | 上一次古法编程是什么时候
前端·javascript·github
whuhewei1 小时前
JS获取CSS动画的旋转角度
前端·javascript·css
蓝黑20202 小时前
Vue组件通信之v-model
前端·javascript·vue
像素之间2 小时前
为什么运行时要加set NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service serve
前端·javascript·vue.js
M ? A2 小时前
Vue转React实战:defineProps精准迁移实战
前端·javascript·vue.js·经验分享·react.js·开源·vureact
西陵2 小时前
别再写 Prompt 了Spec Mode 才是下一代 AI 编程范式
前端·人工智能·ai编程