react Hooks实现原理

news2024/11/28 2:29:50

Fiber

上篇文章fiber简单理解记录了react fiber架构,Hooks是基于fiber链表来实现的。阅读以下内容时建议先了解react fiber。

jsx -> render function -> vdom -> fiber树 -> dom

vdom 转 fiber 的过程称为 recocile。diff算法就是在recocile这个过程中实现。

经过 reconcile 生成新的fiber树。这时候还没有处理副作用(hooks、生命周期等),这些会在reconcile 结束之后处理。

react渲染分为两个阶段:render 和 commit。

render:指 vdom -> fiber 的过程
commit: 指 fiber -> dom 具体操作dom以及执行副作用函数的过程。其包含了三个小阶段:before mutation、mutation(真实操作dom)、 layout。

Hooks

hooks是在哪个阶段处理呢? commit fiber -> dom
hooks的数据保存在哪里呢? fiber 的 memoizedState 链表上存取数据。
是什么时候构造这个链表呢? 在第一次调用 useXxx 的时候

一、 useRef

语法:const refContainer = useRef(initialValue);
作用:useRef 返回一个可变的 ref 对象,其内部只有一个 current 属性被初始化为传入的参数(initialValue)

useRef是怎么实现的呢?

第一次调用 useRef 会走到 mountRef:
在这里插入图片描述
在 mountRef 里可以看到它创建了一个 hook 节点,然后设置了 memoizedState 属性为有 current 属性的对象,也就是 ref 对象。

//以下代码为源码中相关代码缩写,详细过程请看源码
function mountRef<T>(initialValue: T): {current: T} {
  const hook = mountWorkInProgressHook();
  const ref = {current: initialValue};
  hook.memoizedState = ref;
  return ref
}

mountWorkInProgressHook函数用来具体创建 hook 链表
在这里插入图片描述
其第一个节点挂在 fiber 的 memoizedState 属性上,后面的挂在上个节点的 next 属性上。

第二次调用 useRef 会走到 updateRef:
在这里插入图片描述
这里的 updateRef 就是取出 hook 的 momorizedState 的值直接返回了:
在这里插入图片描述
所以 useRef 的返回的 ref 对象始终是最开始那个。

二、useMemo

语法: const cachedValue = useMemo(calculateValue, dependencies)
作用: 它在每次重新渲染的时候能够缓存计算的结果。当依赖的值不变时始终返回之前的值,依赖值变化时创建新的值

那它是怎么实现的呢?

useMemo 同样也是分为 mountMemo 和 updateMemo 两个阶段。

第一次调用 useMemo 会执行 mountMemo
在这里插入图片描述
创建 hook, 执行传入的 nextCreate 函数,把值设置到 hook.memoizedState 属性上。

更新数据时执行的是 updateMemo
在这里插入图片描述
在 updateMemo 的实现中,有一个关键函数 areHookInputsEqual,它用于比较依赖项数组:
如果依赖数组都没变,那就返回之前的值,否则创建新的值更新到 hook.memoizedState。

三、useCallback

语法: const cachedFn = useCallback(fn, dependencies)
作用: 是一个允许你在多次渲染中缓存函数的 React Hook。当依赖的值变化时才执行fn。

那它是怎么实现的呢?

useCallback 同样也是分为 mountCallback 和 updateCallback 两个阶段。

第一次调用 mountCallback
在这里插入图片描述
第二次及以后updateCallback
在这里插入图片描述
其实现和 useMemo 基本一致。其原理都是通过areHookInputsEqual 函数进行依赖项比对,区别在于 useMemo 返回是新数据对象,而 useCallback 返回是回调函数

小结: hook 的数据存放在 fiber 的 memoizedState 属性的链表上,每个 hook 对应一个节点,第一次执行 useXxx 的 hook 会走 mountXxx 的逻辑来创建 hook 链表,之后会走 updateXxx 的逻辑。

今天累了,明天接着总结其他hooks。未完待续。。。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1295901.html

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

相关文章

深入探讨Go语言协程调度:GRM模型解析与优化策略

一、线程调度 1、早期单线程操作系统 一切的软件都是跑在操作系统上&#xff0c;真正用来干活&#xff08;计算&#xff09;的是 CPU早期的操作系统每个程序就是一个进程&#xff0c;直到一个程序运行完&#xff0c;才能进行下一个进程&#xff0c;就是“单进程时代”一切的程…

数据可视化:解锁企业经营的智慧之道

在现代企业管理中&#xff0c;数据可视化已经成为了一项重要的工具。它不仅仅是简单地展示数据&#xff0c;更是提供了深入理解数据、做出更明智决策的方法。作为一名可视化设计从业人员&#xff0c;我经手过一些企业自用的数据可视化项目&#xff0c;今天就来和大家聊聊数据可…

C语言第十七集(待修)

11.30的视频 1.结构体可以这样重新赋值 注:字符数组不能用来赋值 2.匿名结构体重新赋值方法: 注:在创建x时就已经使用过一次匿名结构体了 但是,在使用匿名结构体时,可以一次性创立多个变量 3.结构体内存对齐和对其规则详细搜: 4.总之,我们在创建结构体时,要将占用空间小的成…

一个newman命令行让某大厂瘫痪半天,速看!

newman简介 newman是为Postman而生&#xff0c;专门用来运行Postman编写好的脚本&#xff1b; 使用newman&#xff0c;你可以很方便的用命令行来执行postman collections。 newman的安装 1.先下载Node.js&#xff1b;https://nodejs.org/en/ 2.安装NodeJs(很容易安装&#x…

cmd命令 常用的命令

网络工作为常年公司里的背锅侠&#xff0c;不得不集齐十八般武艺很难甩锅。像cmd命令这种好用又好上手的技术&#xff0c;就是网络工程师上班常备技能。 只要按下快捷键 winR&#xff0c;输入cmd回车&#xff0c;然后输入cmd命令。 像我自己&#xff0c;我就经常用cmd命令检测…

初识优先级队列与堆

1.优先级队列 由前文队列queue可知&#xff0c;队列是一种先进先出(FIFO)的数据结构&#xff0c;但有些情况下&#xff0c;操作的数据可能带有优先级&#xff0c;一般出队列时&#xff0c;可能需要优先级高的元素先出队列&#xff0c;在此情况下&#xff0c;使用队列queue显然不…

xilinx的XVC协议

文章目录 概述JTAG工作方式XVC协议 其他Debug Bridge IP 概述 JTAG工作方式 XVC协议 其他 Debug Bridge IP

cookie总结

cookie和session&#xff1a; 一、Cookie和Session二、使用Cookie保存用户上次的访问时间。三、Cookie常用方法总结乱码问题解决&#xff1a; 一、Cookie和Session 会话&#xff1a;用户从打开浏览器到关闭的整个过程就叫1次会话。 比如有的网站登录过一次&#xff0c;下次再进…

python的websocket方法教程

WebSocket是一种网络通信协议&#xff0c;它在单个TCP连接上提供全双工的通信信道。在本篇文章中&#xff0c;我们将探讨如何在Python中使用WebSocket实现实时通信。 websockets是Python中最常用的网络库之一&#xff0c;也是websocket协议的Python实现。它不仅作为基础组件在…

Spring AOP 概念及其使用

目录 AOP概述 什么是AOP&#xff1f; 什么是Spring AOP ? Spring AOP 快速入门 1.引⼊ AOP 依赖 2.编写AOP程序 Spring AOP 核心概念 1.切点 2.连接点 3.通知 4.切面 通知类型 注意事项: PointCut&#xff08;定义切点&#xff09; 切面优先级 Order 切点表达…

IDEA删除最近打开的文件记录

IDEA删除最近打开的文件记录 遇见问题&#xff1a;如何删除IDEA中最近打开的文件记录 解决方法 先关闭IDEA 找到 recentProjects.xml 文件 windows 位置&#xff1a;&#xff08;AppData是隐藏文件夹&#xff09; 1.C:\Users\电脑用户名\AppData\Roaming\JetBrains\IntelliJIde…

Bash脚本调用百度翻译API进行中文到英文的翻译

写一个bash脚本调用百度翻译API进行中文到英文的翻译&#xff0c;首先需要进行相关的申请。看百度给出的文档链接: 百度翻译API文档 需要先注册一个百度账号&#xff0c;然后申请APPID。脚本中会用到appid和key这两个值。按照文档给出的提示可以获得。如下是脚本&#xff1a; #…

零基础如何入门HarmonyOS开发?

HarmonyOS鸿蒙应用开发是当前非常热门的一个领域&#xff0c;许多人都想入门学习这个技术。但是&#xff0c;对于零基础的人来说&#xff0c;如何入门确实是一个问题。下面&#xff0c;我将从以下几个方面来介绍如何零基础入门HarmonyOS鸿蒙应用开发学习。 一、了解HarmonyOS鸿…

markdown记录

文章目录 基础操作使用一级列表、二级列表 博文链接 基础操作 使用一级列表、二级列表 博文链接 CSDN-Markdown语法集锦 CSDN-markdown语法之如何使用LaTeX语法编写数学公式 CSDN Markdown简明教程1-关于Markdown CSDN Markdown简明教程2-基本使用 CSDN Markdown简明教程3-表…

X86汇编语言:从实模式到保护模式(代码+注释)--c6

X86汇编语言&#xff1a;从实模式到保护模式&#xff08;代码注释&#xff09;–c6 标志寄存器FLAGS&#xff1a; 6th&#xff1a;ZF位&#xff08;Zero Flag&#xff09;&#xff1a;零标志&#xff0c;执行算数或者逻辑运算之后&#xff0c;会将该位置位。10th&#xff1a;D…

油猴(Tampermonkey)浏览器插件简单自定义脚本开发

介绍 浏览器插件&#xff0c;包括油猴插件和其他插件&#xff0c;通过它们可以实现浏览器网页的定制化与功能增强。 其他插件一般只有某种具体的功能&#xff0c;且已经写死而不能更改&#xff0c;比如Adblock插件只用于去广告。 油猴插件是一款用于管理用户脚本的插件&…

RocketMQ - SpringBoot整合RocketMQ

SpringBoot整合RocketMQ 1、快速实战 ​ 按照SpringBoot三板斧&#xff0c;快速创建RocketMQ的客户端。创建Maven工程&#xff0c;引入关键依赖&#xff1a; <dependencies><dependency><groupId>org.apache.rocketmq</groupId><artifactId>r…

HarmonyOS应用开发工具DevEco Studio安装与使用

语雀知识库地址&#xff1a;语雀HarmonyOS知识库 飞书知识库地址&#xff1a;飞书HarmonyOS知识库 知识库内容逐步完善中… 工欲善其事必先利其器&#xff0c;要编写HarmonyOS应用就需要用到官方提供的IDE工具来编写相应的代码。 在鸿蒙开发者官网&#xff0c;其提供了官方的开…

Markdown从入门到精通

Markdown从入门到精通 文章目录 Markdown从入门到精通前言一、Markdown是什么二、Markdown优点三、Markdown的基本语法3.1 标题3.2 字体3.3 换行3.4 引用3.5 链接3.6 图片3.7 列表3.8 分割线3.9 删除线3.10 下划线3.11 代码块3.12 表格3.13 脚注3.14 特殊符号 四、Markdown的高…

Ubuntu 22.04源码安装yasm 1.3.0

sudo lsb_release -r看到操作系统的版本是22.04&#xff0c;sudo uname -r可以看到内核版本是5.15.0-86-generic&#xff0c;sudo gcc --version可以看到版本是11.2.0&#xff0c;sudo make --version可以看到版本是GNU Make 4.3。 下载yasm http://yasm.tortall.net/Downlo…