React16源码: Hooks源码实现
Hooks
1 )概述
- Hooks 在 React16.7版本出现的新功能
- Hooks 改变了整体应用开发的模式,同时开发体验会和以前会变得不一样
- Hooks 让函数组件具有类组件的能力
- 在 function component 里面没有this无法保存 state
- 通过 Hooks可以让 function component 代替 class component
- Hooks 让函数组件变得更强大
2 )用例演示
import React, { useState, useEffect } from 'react'export default () => {const [name, setName] = useState('Wang')useEffect(() => {console.log('component update')return () => {console.log('unbind')}}, [])return (<><p>My Name is: {name}</p><input type="text" value={name} onChange={e => setName(e.target.value)} /></>)
}
- 这里声明了一个functional component ,在以前对比class component它缺少的是什么
- 缺少就是this对象,它没有this对象,那么它就不能有 this.state
- 它就具有包含自己本身的状态的这么一个功能
- 它没有生命周期方法
- 在这里面我们使用了hooks来给我们的组件去存储了 state
- 使用
useState传入了一个默认值是 Wang - 然后它返回一个数组,这是一个数组的解构
- 这个数组第一项是state的对应的这个变量
- 第二项是让我们去改变这个state的方法
- 这就是我们通过useState返回给我们的唯一的两个东西
- 使用
- 然后我们就可以在我们渲染的过程当中去使用这个state了,同样可以去修改这个state
- 比如说我们绑定了这个input的 onchange 事件
- 就是去修改这个state,就是我们的name
- 输入的内容之后它的state就自动更新
- 在下一次渲染的时候能够拿到 state
- 这就是hooks,它给 function component 提供了class component 所具有的能力
- 它的意义不仅仅是为了替代 class compoment
- 是想要去帮助我们去拆分一些在组件内部的逻辑
- 把他们提取出来,能够给更多的组件进行一个复用
- 以前在class compoment 里面是很难去拆分这部分逻辑的
- 还有一个是跟 class component 的最大区别,就是生命周期方法
- 在function component 里面,使用hooks可以通过一个叫做
useEffect的这个API - 这个东西呢我们就可以传入一个方法,这个方法里面
- 比如说,随便写一句 component updated
- 在hooks里面,他没有着重的去区分 mounted 和 updated
- 它的理念是 mounted和updated 都是 updated
- 每一次有组件内容更新的时候都会去调用我们传入的这个 effect 回调函数
- 在function component 里面,使用hooks可以通过一个叫做
- 如果需要事件绑定什么的,之前在unmount的时候,去解除事件绑定,那这时怎么办
- 很简单,看到上面 return一个方法,这个方法就是解除我们的绑定,这边叫做 unbind
- 在目前这种情况下,每一次有更新的时候都会先执行unbind,然后再重新bind
- 这是比较符合react更新的一个逻辑的,就是在它有任何更新的时候
- 都会把之前的状态全部消除,然后返回新的状态
- 当然这对于一些事件监听的绑定不是特别友好, 解决方案如下
- 把它改造成行为,类似于 componentDidMount 和 componentWillUnmount
- 直接在这个 useEffect 传入第二个参数,然后传一个空数组
- 比如说传入一个props来进行一个它是否有变化的一个区分
- 如果传一个空数组,它就没有东西区分,就代表着只要执行一次
- 这样,在输入改变state时,就没有了,只再刷新后,才会执行一次
- 同样,在跳出的时候打印输出了 unbind
- 这就是我们使用 hooks 模拟生命周期方法的一个用法
3 ) 源码分析
这个要在 React 16.7 版本上来找,在 React.js 中可看到
import {useCallback,// ... 很多 khoos
} from './ReactHooks';
现在定位到 ReactHooks.js
/*** Copyright (c) Facebook, Inc. and its affiliates.** This source code is licensed under the MIT license found in the* LICENSE file in the root directory of this source tree.** @flow*/import type {MutableSource,MutableSourceGetSnapshotFn,MutableSourceSubscribeFn,ReactContext,
} from 'shared/ReactTypes';
import type {OpaqueIDType} from 'react-reconciler/src/ReactFiberHostConfig';import invariant from 'shared/invariant';import ReactCurrentDispatcher from './ReactCurrentDispatcher';type BasicStateAction<S> = (S => S) | S;
type Dispatch<A> = A => void;function resolveDispatcher() {const dispatcher = ReactCurrentDispatcher.current;invariant(dispatcher !== null,'Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' +' one of the following reasons:\n' +'1. You might have mismatching versions of React and the renderer (such as React DOM)\n' +'2. You might be breaking the Rules of Hooks\n' +'3. You might have more than one copy of React in the same app\n' +'See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.',);return dispatcher;
}export function useContext<T>(Context: ReactContext<T>,unstable_observedBits: number | boolean | void,
): T {const dispatcher = resolveDispatcher();if (__DEV__) {if (unstable_observedBits !== undefined) {console.error('useContext() second argument is reserved for future ' +'use in React. Passing it is not supported. ' +'You passed: %s.%s',unstable_observedBits,typeof unstable_observedBits === 'number' && Array.isArray(arguments[2])? '\n\nDid you call array.map(useContext)? ' +'Calling Hooks inside a loop is not supported. ' +'Learn more at https://reactjs.org/link/rules-of-hooks': '',);}// TODO: add a more generic warning for invalid values.if ((Context: any)._context !== undefined) {const realContext = (Context: any)._context;// Don't deduplicate because this legitimately causes bugs// and nobody should be using this in existing code.if (realContext.Consumer === Context) {console.error('Calling useContext(Context.Consumer) is not supported, may cause bugs, and will be ' +'removed in a future major release. Did you mean to call useContext(Context) instead?',);} else if (realContext.Provider === Context) {console.error('Calling useContext(Context.Provider) is not supported. ' +'Did you mean to call useContext(Context) instead?',);}}}return dispatcher.useContext(Context, unstable_observedBits);
}export function useState<S>(initialState: (() => S) | S,
): [S, Dispatch<BasicStateAction<S>>] {const dispatcher = resolveDispatcher();return dispatcher.useState(initialState);
}export function useReducer<S, I, A>(reducer: (S, A) => S,initialArg: I,init?: I => S,
): [S, Dispatch<A>] {const dispatcher = resolveDispatcher();return dispatcher.useReducer(reducer, initialArg, init);
}export function useRef<T>(initialValue: T): {|current: T|} {const dispatcher = resolveDispatcher();return dispatcher.useRef(initialValue);
}export function useEffect(create: () => (() => void) | void,deps: Array<mixed> | void | null,
): void {const dispatcher = resolveDispatcher();return dispatcher.useEffect(create, deps);
}export function useLayoutEffect(create: () => (() => void) | void,deps: Array<mixed> | void | null,
): void {const dispatcher = resolveDispatcher();return dispatcher.useLayoutEffect(create, deps);
}export function useCallback<T>(callback: T,deps: Array<mixed> | void | null,
): T {const dispatcher = resolveDispatcher();return dispatcher.useCallback(callback, deps);
}export function useMemo<T>(create: () => T,deps: Array<mixed> | void | null,
): T {const dispatcher = resolveDispatcher();return dispatcher.useMemo(create, deps);
}export function useImperativeHandle<T>(ref: {|current: T | null|} | ((inst: T | null) => mixed) | null | void,create: () => T,deps: Array<mixed> | void | null,
): void {const dispatcher = resolveDispatcher();return dispatcher.useImperativeHandle(ref, create, deps);
}export function useDebugValue<T>(value: T,formatterFn: ?(value: T) => mixed,
): void {if (__DEV__) {const dispatcher = resolveDispatcher();return dispatcher.useDebugValue(value, formatterFn);}
}export const emptyObject = {};export function useTransition(): [(() => void) => void, boolean] {const dispatcher = resolveDispatcher();return dispatcher.useTransition();
}export function useDeferredValue<T>(value: T): T {const dispatcher = resolveDispatcher();return dispatcher.useDeferredValue(value);
}export function useOpaqueIdentifier(): OpaqueIDType | void {const dispatcher = resolveDispatcher();return dispatcher.useOpaqueIdentifier();
}export function useMutableSource<Source, Snapshot>(source: MutableSource<Source>,getSnapshot: MutableSourceGetSnapshotFn<Source, Snapshot>,subscribe: MutableSourceSubscribeFn<Source, Snapshot>,
): Snapshot {const dispatcher = resolveDispatcher();return dispatcher.useMutableSource(source, getSnapshot, subscribe);
}
-
定位到 useState
export function useState<S>(initialState: (() => S) | S, ): [S, Dispatch<BasicStateAction<S>>] {const dispatcher = resolveDispatcher();return dispatcher.useState(initialState); }- 这边调用了一个
dispatcher.useState(initialState); - 这个dispatch等于
const dispatcher = resolveDispatcher();
- 这边调用了一个
-
对应的再去找到这个 resolveDispatcher ,它是个function
function resolveDispatcher() {const dispatcher = ReactCurrentOwner.currentDispatcher;invariant(dispatcher !== null,'Hooks can only be called inside the body of a function component.',);return dispatcher; }- 可看到是通过
ReactCurrentOwner.currentDispatcher去获取的 - 这个就要涉及到后续react-dom渲染的过程
- 在我们使用阶段,是没有拿到任何真正节点的实例的。
- 比如在我们创建了react element,我们传进去的是这个class component的类
- 而不是它的一个new的一个实例,拿不到对应的东西
- 只有在 react-dom 进行真正的渲染的过程当中,才会去为我们创建这个实例
- 它这边提供了这个方法,在实际调用是要在我们的 react-dom进行渲染的时候
- 它才会为我们这个
ReactCurrentOwner去设置属性
- 可看到是通过
-
ReactCurrentOwner 它是一个全局的类,定位一下
/*** Copyright (c) Facebook, Inc. and its affiliates.** This source code is licensed under the MIT license found in the* LICENSE file in the root directory of this source tree.** @flow*/import type {Fiber} from 'react-reconciler/src/ReactFiber'; import typeof {Dispatcher} from 'react-reconciler/src/ReactFiberDispatcher';/*** Keeps track of the current owner.** The current owner is the component who should own any components that are* currently being constructed.*/ const ReactCurrentOwner = {/*** @internal* @type {ReactComponent}*/current: (null: null | Fiber),currentDispatcher: (null: null | Dispatcher), };export default ReactCurrentOwner; -
我们可以看到 ReactCurrentOwner ,它就是一个对象,里面有两个属性
-
一个是 current , 就是这个current就对应正在目前正在渲染的哪一个节点的一个实例
-
currentDispatcher 是实例对应的 dispatcher
-
它一开始初始化的时候,是两个 null
-
然后到后期每一个组件进行渲染的时候,它才会进行一个渲染
-
就跟我们在class component里面看到的,它的 setState 调用的是 this.updateSetState
-
在这里的 dispatch 也是从不同平台上面,它传入进来的一个东西,不是我们在react中定义的
-
所以在react中我们可以看到的源码就非常的简单,就是这么一些相关的东西
-
同理,useEffect和其他内容也基本是类似的,只不过它最终调用的方法会不一样
-
比如说useReducer,那么它调用的是 dispatcher.useReducer
-
它们最终都是调用 dispatcher 上面的方法
相关文章:
React16源码: Hooks源码实现
Hooks 1 )概述 Hooks 在 React16.7版本出现的新功能Hooks 改变了整体应用开发的模式,同时开发体验会和以前会变得不一样Hooks 让函数组件具有类组件的能力 在 function component 里面没有this无法保存 state通过 Hooks可以让 function component 代替…...
华为端口隔离高级用法经典案例
最终效果: pc4不能ping通pc5,pc5能ping通pc4 pc1不能和pc2、pc3通,但pc2和pc3能互通 vlan batch 2 interface Vlanif1 ip address 10.0.0.254 255.255.255.0 interface Vlanif2 ip address 192.168.2.1 255.255.255.0 interface MEth0/0/1 i…...
java项目启动jar包启动参数设置端口号
默认启动 java -jar myapp.jar 指定配置文件 java -jar myapp.jar --spring.profiles.activedev 指定端口号 java -jar myapp.jar --server.port8080 后台启动 nohup java -jar myapp.jar --server.port8080 >outlog.log 2>&1 &...
【数据结构和算法】寻找数组的中心下标
其他系列文章导航 Java基础合集数据结构与算法合集 设计模式合集 多线程合集 分布式合集 ES合集 文章目录 其他系列文章导航 文章目录 前言 一、题目描述 二、题解 2.1 前缀和的解题模板 2.1.1 最长递增子序列长度 2.1.2 寻找数组中第 k 大的元素 2.1.3 最长公共子序列…...
多粒度在研究中的应用
FontDiffuser: One-Shot Font Generation via Denoising Diffusion with Multi-Scale Content Aggregation and Style Contrastive Learning 存在的问题 现有的字体生成方法虽然取得了令人满意的性能,但在处理复杂字和风格变化较大的字符(尤其是中文字符)时&#x…...
Docker命令---查看容器日志
介绍 使用docker命令查看容器输出的日志 示例 docker logs 容器ID...
Spring Boot 基于Redisson实现注解式分布式锁
依赖版本 JDK 17 Spring Boot 3.2.0 Redisson 3.25.0 源码地址:Gitee 导入依赖 <properties><redisson.version>3.25.0</redisson.version> </properties><dependencies><dependency><groupId>org.projectlombok</…...
Javascript 正则表达式零宽断言
在介绍正则表达式零宽断言这个概念之前,先看一下以下这道有关 javascript 正则表达式的题目: 登录注册流程是前端最常见的业务流程之一,注册流程少不了密码强弱度校验,请实现对密码的校验,要求满足: 包含大…...
Chocolatey
Chocolatey Software | PHP (Hypertext Preprocessor) 8.3.1 msi安装包https://github.com/chocolatey/choco/releases/download/2.2.2/chocolatey-2.2.2.0.msi 设置/安装 巧克力味Chocolatey CLI (choco)设置/安装 要求 受支持的 Windows 版本Windows …...
雍禾植发成毛发行业标杆!雍禾医疗获“年度医疗大健康消费企业”
近期,以“新视野 新链接”为主题的2023 EDGE AWARDS全球创新评选榜单正式发布。该评选由钛媒体发起,聚焦大健康产业,由权威行业专家、王牌分析师、专业投资机构、用户代表共同评审,兼顾综合专业性、影响力、创新性三大维度评选而出…...
Linux内核--进程管理(十二)共享内存和信号量
目录 一、引言 二、基础知识 三、统一封装的接口 ------>3.1、kern_ipc_perm 四、共享内存的创建和映射 ------>4.1、创建共享内存 ------>4.2、共享内存的映射 五、信号量的创建和使用 ------>5.1、信号量的创建 ------>5.2、信号量的初始化 ------…...
java 构造方法
构造方法 1、什么是构造方法,有什么用? 构造方法是一个比较特殊的方法,通过构造方法可以完成对象的创建,以及实例变量的初始化。 换句话说:构造方法是用来创建对象,并且同时给对象的属性赋值。 注意&#x…...
CISSP 第2章: 人员安全和风险管理概念
第二章 人员安全和风险管理概念 2.1 促进人员安全策略 构建工作描述方面的重要因素包括: 职责分离: 把关键的、重要的和敏感工作任务分配给若干不同的管理员或高级执行者,防止共谋 工作职责:最小特权原则 岗位轮换:提供知识冗余,减少伪造、数据更改、偷…...
前端八股文(CSS篇)一
目录 1.px和em的区别 2.介绍下BFC及其应用 3.介绍下粘性布局(sticky) 4.清除浮动的方法 5.如何用css或js实现多行文本溢出省略效果,考虑兼容 6.如何触发重排和重绘? 7.重绘与重排的区别? 8.说说两种盒模型以及区…...
游戏加速器LSP/DLL导致WSL.EXE无法打开问题修复!
解决办法: https://github.com/microsoft/WSL/issues/4177#issuecomment-597736482 方法一:(管理员身份) netsh winsock reset 方法二: WSCSetApplicationCategory 函数设置LSP加载权限 bool NoLsp(const wchar_t* …...
宏电股份5G RedCap终端产品助力深圳极速先锋城市建设
12月26日,“全城全网,先锋物联”深圳移动5G-A RedCap助力深圳极速先锋城市创新发布会举行,宏电股份携一系列5G RedCap终端产品应邀参与创新发布会,来自全国5G生态圈的各界嘉宾、专家学者济济一堂,共探信息化数字化创新…...
linux top命令中 cpu 利用率/mem 使用率与load average平均负载计算方式
文章目录 1 简介2 CPU% 字段3 MEM% 字段4 load average 平均负载 1 简介 top 命令是 Linux 上一个常用的系统监控工具,它经常用来监控 Linux 的系统状态,是常用的性能分析工具,能够显示较全的系统资源信息,包括系统负载ÿ…...
win11出现安全中心空白和IT管理员已限制对某些区域的访问(不一样的解决方式),真实的个人经历,并且解决经过
1、个人的产生问题的经历 2023年12月22日,由于我买了一块电脑的固态硬盘1T,想要扩容,原来电脑自带512G(由于个人是一个程序员,导致512G实在太古鸡肋)装好以后,想要重装一下系统,来个大清理。结果不出意料&…...
关于安卓重启设备和重启应用进程
android 重启应用进程 //多种方式重启应用进程public class MainActivity {//重启当前Applicationprivate void restartApplication(){final Intent intent getPackageManager().getLaunchIntentForPackage(getPackageName());intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP…...
Linux内核--进程管理(十三)O(1)调度算法
目录 一、引言 二、O(1)调度算法原理 ------>2.1、prio_array 结构 ------>2.2、runqueue 结构 三、实时进程调度 四、普通进程调度 ------>4.1、运行时间片计算 五、O(1)调度算法实现 ------>5.1、时钟中断任务调度 ------>5.2、任务调度 一、引言 …...
Chapter03-Authentication vulnerabilities
文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...
大数据学习栈记——Neo4j的安装与使用
本文介绍图数据库Neofj的安装与使用,操作系统:Ubuntu24.04,Neofj版本:2025.04.0。 Apt安装 Neofj可以进行官网安装:Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...
Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...
智能AI电话机器人系统的识别能力现状与发展水平
一、引言 随着人工智能技术的飞速发展,AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术,在客户服务、营销推广、信息查询等领域发挥着越来越重要…...
【Linux】Linux 系统默认的目录及作用说明
博主介绍:✌全网粉丝23W,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...
RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill
视觉语言模型(Vision-Language Models, VLMs),为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展,机器人仍难以胜任复杂的长时程任务(如家具装配),主要受限于人…...
