当前位置: 首页 > news >正文

React Hooks 内部实现原理与函数组件更新机制

React Hooks 内部实现原理与函数组件更新机制

Hooks 的内部实现原理

React Hooks 的实现依赖于以下几个关键机制:

1. 链表结构存储 Hook 状态

React 使用单向链表来管理 Hooks 的状态。每个 Hook 节点包含:

type Hook = {memoizedState: any,      // 存储当前状态baseState: any,          // 基础状态baseQueue: Update<any, any> | null, // 基础更新队列queue: UpdateQueue<any, any> | null, // 更新队列next: Hook | null,       // 指向下一个 Hook
};

2. 当前 Hook 指针

React 内部维护一个 currentHook 指针,它会随着组件的渲染过程依次指向链表中的每个 Hook:

let currentlyRenderingFiber: Fiber | null = null;
let currentHook: Hook | null = null;
let workInProgressHook: Hook | null = null;

3. Hooks 调用顺序的重要性

Hooks 必须无条件地在组件顶层调用,这是因为 React 依赖于调用顺序来正确关联 Hook 和它的状态:

function updateFunctionComponent(fiber) {// 重置指针currentlyRenderingFiber = fiber;fiber.memoizedHooks = null;currentHook = null;workInProgressHook = null;// 执行组件函数const children = Component(props);// 渲染完成后重置currentlyRenderingFiber = null;currentHook = null;workInProgressHook = null;return children;
}

函数组件更新机制

1. 调度阶段

当状态更新时,React 会:

  1. 创建一个更新对象并加入更新队列
  2. 调度一次新的渲染(通过 scheduleUpdateOnFiber

2. 渲染阶段

在渲染阶段,React 会:

  1. 调用函数组件
  2. 按顺序执行 Hooks
  3. 返回新的 React 元素
function renderWithHooks(current, workInProgress, Component, props) {// 设置当前正在渲染的 FibercurrentlyRenderingFiber = workInProgress;// 重置 Hook 链表workInProgress.memoizedState = null;// 执行组件函数const children = Component(props);// 重置状态currentlyRenderingFiber = null;return children;
}

3. 提交阶段

在提交阶段,React 会将渲染结果应用到 DOM 上,并执行副作用(useEffect 等)。

常见 Hook 的实现原理

useState

function useState(initialState) {return useReducer(basicStateReducer,initialState);
}function basicStateReducer(state, action) {return typeof action === 'function' ? action(state) : action;
}

useEffect

function useEffect(create, deps) {const fiber = currentlyRenderingFiber;const effect = {tag: HookEffectTag, // 标识是 effectcreate,             // 副作用函数destroy: undefined,  // 清理函数deps,               // 依赖数组next: null,         // 下一个 effect};// 将 effect 添加到 fiber 的 updateQueueif (fiber.updateQueue === null) {fiber.updateQueue = { lastEffect: null };}const lastEffect = fiber.updateQueue.lastEffect;if (lastEffect === null) {fiber.updateQueue.lastEffect = effect.next = effect;} else {const firstEffect = lastEffect.next;lastEffect.next = effect;effect.next = firstEffect;fiber.updateQueue.lastEffect = effect;}
}

useMemo

function useMemo(nextCreate, deps) {const hook = mountWorkInProgressHook();const nextDeps = deps === undefined ? null : deps;const nextValue = nextCreate();hook.memoizedState = [nextValue, nextDeps];return nextValue;
}

关键点总结

  1. Hooks 依赖于调用顺序:React 使用链表结构按顺序存储 Hook 状态,因此不能在条件或循环中使用 Hooks。

  2. 双缓存技术:React 使用 current 和 workInProgress 两棵树来实现异步可中断的渲染。

  3. 闭包陷阱:函数组件每次渲染都会创建新的闭包,这解释了为什么有时候会拿到旧的 state 或 props。

  4. 批量更新:React 会合并多个状态更新,避免不必要的重复渲染。

  5. 副作用调度:useEffect 的副作用会在浏览器完成布局与绘制之后延迟执行。

理解这些原理有助于编写更高效、更可靠的 React 应用,并能更好地调试 Hook 相关的问题。

http://www.dtcms.com/a/267129.html

相关文章:

  • 【LeetCode 热题 100】73. 矩阵置零——(解法二)空间复杂度 O(1)
  • stm32的三种开发方式
  • Zigbee/Thread
  • 车载以太网-防火墙
  • 【深度学习】强化学习(Reinforcement Learning, RL)主流架构解析
  • 2025使用VM虚拟机安装配置Macos苹果系统下Flutter开发环境保姆级教程--下篇
  • React Native 开发环境搭建--mac--android--奔溃的一天
  • App爬虫实战篇-以华为真机手机爬取集换社的app为例
  • Pytest 测试发现机制详解:自动识别测试函数与模块
  • 在 Ubuntu 下配置 oh-my-posh —— 普通用户 + root 各自使用独立主题(共享可执行)
  • Redis Cluster 与 Sentinel 笔记
  • 文本方式和二进制方式打开文件的不同
  • Flutter 使用http库获取网络数据的方法(一)
  • Excel 数据透视表不够用时,如何处理来自多个数据源的数据?
  • MAX3485在MCU芯片AS32S601-485通信外设中的应用
  • 线程的礼让和加入
  • 1004、最大连续1的个数 III
  • SpringBatch使用介绍
  • 任务调度器(Scheduler)实现逻辑
  • Java 创建对象过程 JVM 内存分配并发安全笔记
  • JVM与JMM
  • Mysql底层专题(四)索引优化实战一
  • DeepSeek与诡秘之主
  • 在SoC数据加解密验证中使用 Python 的 gmssl 库
  • 03_性能优化:让软件呼吸更顺畅
  • 计算机网络(网页显示过程,TCP三次握手,HTTP1.0,1.1,2.0,3.0,JWT cookie)
  • 【网络协议安全】任务12:二层物理和单臂路由及三层vlanif配置方法
  • HarmonyOS:创建ArkTS卡片
  • 从零开始开发纯血鸿蒙应用之探析仓颉语言与ArkTS的差异
  • Vuex身份认证