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.pswp.cn/pingmian/87871.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/87871.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

分布式会话的演进和最佳实践,含springBoot 实现(Java版本)

一、分布式会话的背景 在微服务架构或集群部署环境下&#xff0c;请求可能落在不同的服务器节点&#xff0c;无法再依赖本地内存来维护用户 Session。因此&#xff0c;需要一种跨节点共享 Session 的机制&#xff0c;这就是 分布式会话管理的核心目标。二、分布式会话的演进历程…

ch03 部分题目思路

G. 收集 由于稀有度相同的物品需要一起处理&#xff0c;我们先把他们聚集到一起。 类似这样&#xff1a; vector<int> g[maxn]; ... {cin >> x >> c;g[c].push_back(x); }那么我们需要一个贪心的思路&#xff1a; 肯定是按 ccc 从小往大收集的&#xff1b;对…

Django多表查询(ORM)

1、建立表结构 三个表&#xff1a;book、Author、publisher。 书籍和作者是多对多的关系&#xff0c;一本书可以有多个作者&#xff0c;一个作者可以有多本书。 出版社和书籍是一对多的关系&#xff0c;一个出版社可以出版多本书&#xff08;多方&#xff0c;多方定义外键&…

C# 集合表达式和展开运算符 (..) 详解

集合表达式 (Collection Expressions)基本语法支持的集合类型展开运算符 (..)基本用法实际应用示例创建新集合合并集合与现有API结合性能考虑高级用法多维集合自定义集合注意事项与传统方式的比较总结集合表达式 (Collection Expressions) C# 12 引入了集合表达式&#xff0c;…

数学视频动画引擎Python库 -- Manim Voiceover 安装 Installation

文中内容仅限技术学习与代码实践参考&#xff0c;市场存在不确定性&#xff0c;技术分析需谨慎验证&#xff0c;不构成任何投资建议。 Manim Voiceover 是一个为 Manim 打造的专注于语音旁白的插件&#xff1a; 直接在 Python 中添加语音旁白&#xff1a; 无需使用视频编辑器&…

Git安装避坑指南:新手村通关秘籍

Git安装避坑指南&#xff1a;新手村通关秘籍 刚学编程那会儿&#xff0c;Git安装差点让我砸键盘。满心欢喜打开官网下载&#xff0c;结果卡在配置上&#xff0c;命令行死活不认识git命令。看着教程里别人行云流水的操作&#xff0c;自己对着报错信息干瞪眼——这感觉&#xff…

如何修改Siteground max_execution_time值?

这个值在Siteground 上是修改不了的。 以下是来自Siteground 官网的解释&#xff1a; 由于服务器上全局定义的 PHP 限制&#xff0c;某些 PHP 设置无法更改。最常见的无法更改的 PHP 设置包括&#xff1a; memory_limit max_execution_time max_input_time post_max_size up…

【libm】 11 fmin函数 (fmin.rs)

一、源码 这段代码实现了一个符合 IEEE 754-2008 标准的 minNum 函数&#xff08;在 Rust 中命名为 fmin&#xff09;&#xff0c;该功能在 IEEE 754-2019 标准中已被 minimumNumber 取代。 /* SPDX-License-Identifier: MIT OR Apache-2.0 */ //! IEEE 754-2008 minNum. Thi…

React 英语单词消消乐一款专为英语学习设计的互动式记忆游戏

&#x1f4d6; 项目简介 英语单词消消乐 是一款专为英语学习设计的互动式记忆游戏。通过经典的消消乐玩法&#xff0c;让用户在轻松愉快的游戏中掌握英语单词&#xff0c;提高词汇量和记忆效果。 &#x1f3af; 项目目标 让英语学习变得有趣且高效通过游戏化方式增强单词记忆…

Qt:QPushButton、QRadioButton、QCheckBox

目录 一、QPushButton 1.认识QPushButton 2.设置按钮图标 3.设置按钮的快捷键 二、QRadioButton 常用的信号 按钮的分组 三、QCheckBox 一、QPushButton 1.认识QPushButton QPushButton继承自QWidget&#xff0c;所以在上一篇文章中介绍的QWidget的属性&#xff0c;理…

docker 无法拉取镜像解决方法

目录 我在omv中通过后台页面拉取alist镜像总是失败&#xff0c;原因千奇百怪 今天再战终于解决首先&#xff0c;到dockerhub找镜像和wiki进入docker账号设置 找到里面提示了登录操作和密码命令行中执行后会提示成功之后按需配置代理&#xff0c;同时检查自己的配置检查 Docker …

安卓10.0系统修改定制化_____安卓9与安卓10系统文件差异 有关定制选项修改差异

在修改安卓10的rom之前。我们需要对rom有简单的了解。区分安卓10与安卓9之间的差异。了解不同安卓版本之间系统文件的变化以及权限的区别。对于修改一些定制化选项有很大的辅助作用. 通过博文了解💝💝💝 1💝💝💝-----安卓10与安卓9之间文件实例对比 了解差异 …

HTML表单元素全面指南:从基础到实践

引言 HTML表单是网页开发中不可或缺的一部分&#xff0c;它为用户提供了与网站交互的途径。无论是简单的登录页面还是复杂的数据提交界面&#xff0c;表单元素都扮演着关键角色。本文将详细介绍各种HTML表单元素及其使用方法。 输入框(input元素) input元素是最基础也是最灵…

深度学习的核心理论与技术

理解深度学习的基本原理、核心算法和关键技术 深度学习的核心理论与技术前言一、深度学习核心理论1. 神经网络基础核心内容练习资源2. 反向传播与梯度下降核心内容练习资源3. 卷积神经网络&#xff08;CNN&#xff09;核心内容练习资源4. 循环神经网络&#xff08;RNN&#xff…

LinkedList 链表数据结构实现 (OPENPPP2)

&#x1f50d; LinkedList 链表数据结构实现 (OPENPPP2) &#x1f9f1; 1. 数据结构设计 LinkedListNode 结构 #mermaid-svg-XDJqt6cHMKxodJLG {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-XDJqt6cHMKxodJLG .er…

RPC/gRPC入门学习

一、RPC 1.1 RPC概念 RPC Remote Procedure Call, 即远程过程调用&#xff0c;是一种用于构建分布式系统的理念&#xff0c;在一些资料中被称为“请求-响应”协议。两个进程可以位于同一系统中&#xff0c;也可以位于不同的系统中&#xff0c;通过网络相互连接。 RPC使程…

租车小程序电动车租赁小程序php方案

电动车租赁小程序源码&#xff0c;开发语言后端php&#xff0c;前端uniapp。四个端&#xff1a;用户端门店端分销商端小程序&#xff0c;pc管理后台。一 用户端&#xff1a;可以扫门店码&#xff0c;进入门店详情页。也可以通过地图找车。或者门店列表进入&#xff0c;或者快速…

Python数据分析基础04:预测性数据分析

相关章节&#xff1a; 《Python数据分析基础03&#xff1a;探索性数据分析》 《python数据分析基础02&#xff1a;数据可视化分析》 《Python数据分析基础01&#xff1a;描述性统计分析》 预测性数据分析&#xff08;Predictive Analytics&#xff09; 的深度解析&#xff0…

PFAE(Pyramidal Frequency Attention Extraction)通过频域注意力机制提高边界模糊、遮挡等场景的的检测能力

在伪装物体检测中&#xff0c;现有方法多依赖空间局部特征&#xff0c;难以捕捉全局信息&#xff0c;而 Transformer 类方法计算成本高昂。频率域特征因具备全局建模能力&#xff0c;可有效抑制背景噪声、提升伪装物体语义清晰度&#xff0c;但频域与空域的频繁转换会增加计算复…

AE插件安装方法

Adobe After Effects简称AE&#xff0c;是adobe公司开发的一个视频剪辑及设计软件&#xff0c;AE软件能够实现对素材的非线性编辑而完成画面的组接&#xff0c;同时还能对任何一部分进行修改&#xff0c;达到想要的结果。AE含有很多脚本、常用的表达式和插件&#xff0c;做动画…