React的useEvent 和 ahooks 的 useMemorizedFn 的深度分析和对比
父组件
const TestParent: React.FC<any> = () => {const [State, setState] = useState(0);const changeFun = useCallback(() => {console.log('useCallback closure 里的 State', State);}, [State]);const changeFun_useEvent = useEvent(() => {console.log('useEvent closure 里的 State', State);});const changeFun_usememrized = useMemorizedFn(() => {console.log('useMemorizedFn closure 里的 State', State);});return (<div style={{ width: '100%', padding: '20px', backgroundColor: 'green' }}>父组件的state: {State}<button onClick={() => setState(Math.random())}>click-change state</button><TestChild changeFun={changeFun_useEvent}></TestChild><TestChild changeFun={changeFun_usememrized}></TestChild></div>);
};
子组件
const TestChild = (props: any) => {const { changeFun } = props;useEffect(() => {console.log('changeFun-》地址change了,导致了子组件刷新了。');}, [changeFun]);return (<div style={{ backgroundColor: 'pink' }}>子组件<br /><br /><button onClick={changeFun}>child click - get parent's state </button></div>);
};
React.memo(TestChild);
useEvent
已被官方废弃
useEvent 源码解析
【解释1】
1、由于每次父组件更新,都会执行到 下面的代码。这个是首要条件!

2、其次,每次执行都会传递过来一个新的handler,自然带来了新的闭包、新的数据。
3、最后,useLayoutEffect的作用是每次数据发生更新,自动的去执行里面的方法。
4、 所以 handlerRef.current 就能拿到带着最新数据的一个handler
【解释2】
useCallback 并且依赖为[],只执行一次,地址也就永远不会变了。
那么,useEvent()return出去函数的地址永不变化。
可以解释为
1、useEvent() return 出去了一个对象,为 obj = {A:{}}2、 useCallback里的箭头函数return出去的是这个 fn=handlerRef.current;相当于一个属性 A 由于handlerRef.current指向地址是不停变化的,所以A得指向地址就是不停变化的。3、因此我们真正使用 changeFun_useEvent=useEvent(xx)的时候, 拿到的是obj。永远不变的地址。changeFun_useEvent()调用的时候拿到的就是obj.A了。就是最新的带着最新数据的一个handler
function useEvent(handler: any) {const handlerRef = useRef(null);// In a real implementation, this would run before layout effects// 这行保证handlerRef一直处于,最新的闭包、拿到最新的数据。【解释1】useLayoutEffect(() => {console.log('useLayoutEffect执行了');handlerRef.current = handler;});
//这行保证返回的数据地址永远不变,但是执行的时候拿到的最新的。【解释2】return useCallback((...args: any) => {// In a real implementation, this would throw if called during renderconst fn = handlerRef.current;return fn(...args);}, []);
}
useMemorizedFn源码解析
源码地址
【解释1】
fn在这里做依赖的原因: 由于每次父组件重新执行,都会走到useMemorizedFn里并传过来一个新的箭头函数。所以fn每次地址都是新的。也就带来了新数据的闭包。fnRef.current也就是解释2里的A的地址每次都是新的,带着新的数据的闭包。
【解释2】
这里可以解释为: const obj = {A:{}} ;
memoizedFn.current = obj;
fnRef.current = A
当执行memoizedFn.current的时候也就是去访问并执行了 obj.A
function useMemorizedFn(fn: any) {const fnRef = useRef(fn);// 这行保证fn一直处于,最新的闭包、拿到最新的数据。【解释1】//这里为什么不直接 fnRef.current = fn ,可参考官网。总结就是 fnRef.current的需要放到useMemo。否则reactdev tool监听不到变化。fnRef.current = useMemo(() => {console.log('useMemo执行了'); // 父级改变就执行return fn;}, [fn]);const memoizedFn = useRef<any>();// 下面保证fn引用地址不变、且每次都能拿到最新的闭包 【解释2】if (!memoizedFn.current) {memoizedFn.current = function (this: any, ...args: any) {return fnRef.current.apply(this, args);//立即执行、改变this指向、传递参数 3个作用};}return memoizedFn.current;
}
总结
由此我们看出。其实二者的原理和出发点都是一致的,都是返回的是个固定的对象obj,该对象地址不变,但是调用的方法的时候相当于调用了obj.A,此属性的指向是会一直更新的。
只不过更新的时候 :useevent用了useLayoutCallback做更新,useMemorizedFn则使用了useMemo。
保持地址不变的时候:useevent用的是useCallback ,useMemorizedFn使用的一个 !memoizedFn.current + 新固定的function 。
此文纯属个人理解,有偏差望指正。
相关文章:
React的useEvent 和 ahooks 的 useMemorizedFn 的深度分析和对比
父组件 const TestParent: React.FC<any> () > {const [State, setState] useState(0);const changeFun useCallback(() > {console.log(useCallback closure 里的 State, State);}, [State]);const changeFun_useEvent useEvent(() > {console.log(useEv…...
基于goframe2.5.4、vue3、tdesign-vue-next开发的全栈前后端分离的管理系统
goframe-admin goframe-admin V1.0.0 平台简介 基于goframe2.5.4、vue3、tdesign-vue-next开发的全栈前后端分离的管理系统。前端采用tdesign-vue-next-starter 、vue3、pinia、tdesign-vue-next。 特征 高生产率:几分钟即可搭建一个后台管理系统认证机制&#x…...
LInux之在同一Tomcat下使用不同的端口号访问不同的项目
🎉🎉欢迎来到我的CSDN主页!🎉🎉 🏅我是君易--鑨,一个在CSDN分享笔记的博主。📚📚 🌟推荐给大家我的博客专栏《LInux实战开发》。🎯🎯 …...
梦百合上榜2023鼎革奖数字化转型先锋榜
10月26日,第六届“鼎革奖”数字化转型先锋榜单揭晓,梦百合家居凭借数字化生产的卓越成果——SAP管理平台及供应链项目,入选2023【鼎革奖】数字化转型先锋榜年度供应链转型典范,梦百合家居COO 崔慧明同步入选2023【鼎革奖】数字化转型先锋榜年度首席运营官。 据了解,「鼎革奖」数…...
沉痛悼念科研分公司
今天上班途中,遇到了上家公司的同事王强。他正准备去体检中心体检。几句寒暄之后,得知他是要入职选煤公司了。 我们所在的公司比较大,总公司下设有几十个分、子公司,我和他曾经在一家子公司——科研分公司。现在的科研分公司解散…...
Django的网站项目开发好了,该用何种方案在Centos上部署【答:Gunicorn(uWSGI)+Nginx】
问:用Django开发的网站开发好了,现在要部署上线。 系统为Centos 7.x 现在我安装好Django和相关依赖后,我用命令 python manage.py runserver 127.0.0.1:8010 启动Django 然后安装配置好Nginx,并把用的请求转发到 127.0.0.1:8010 。 请问这样的…...
基于PyTorch的中文情绪分析器设计与开发
收藏和点赞,您的关注是我创作的动力 文章目录 概要 一、相关基础理论2.1 主流深度学习框架2.2 神经网络2.2.1 神经网络基础 二、中文情感分类模型构建3.1 开发环境3.2 数据部分3.3 文本特征提取3.3.1、过滤标点符号3.3.2 中文分词、单词过滤 三 运行结果与分析五 结…...
HT5010 音频转换器工作原理
HT5010是一款低成B的立体声DA转换器,内部集成了内插滤波器、DA转换器和输出模拟滤波等电路。其可支持多种音频数字输入格式,支持24-bit字节。 该HT5010 基于一个多比特位的Δ-Σ调制器,将数字信号转化成两个声道的模拟信号并经过模拟滤波器滤…...
ubuntu18.04如何更新到22.04
将linux系统中的Ubuntu 18.04更新到22.04,按照以下步骤操作: 打开终端并更新系统,使用以下命令: sudo apt update sudo apt upgrade sudo apt dist-upgrade 确保系统是最新的,然后备份数据,以防万一。执…...
嵌入式软件开发:第二部分–七个步骤计划
使用一种工具(仅一种工具)武装自己,您可以在下一个嵌入式项目的质量和交付时间上做出巨大的改进。点击领取嵌入式物联网学习路线 该工具是:绝对承诺对开发代码的方式进行一些小而基本的更改 。 有了改变的意志,今天您…...
什么是IPA,和RPA有啥区别和联系?
∵ IPA中包含了RPA的“PA”,AI的“I” ∴IPARPAAI,等式成立! AI:或人工智能,是一种复杂的计算机技术,旨在模仿人类智能行为和决策的能力。它涵盖了多种技术和方法,包括:机器学习&am…...
内涝积水监测仪怎么样?万宾科技城市内涝积水监测的作用
在城市建设发展过程中,道路基础设施的建设永远都占据着重要一席,因为人们出行一旦受阻便会影响城市进展,也会影响经济发展。在城市之中有隧道,下穿式立交桥等容易存积水的地方,一旦出现恶劣暴雨天气,这些地…...
【java】命令行,包
文件夹情况: HelloWorld.java package com.demo; public class HelloWorld{public static void print(){System.out.println("HelloWorld!");}public static void main(String[] args){print();} } import.java import com.demo.HelloWorld; public cla…...
Generative AI 新世界 | 文生图(Text-to-Image)领域论文解读
在上期文章,我们开始探讨生成式 AI(Generative AI)的另一个进步迅速的领域:文生图(Text-to-Image)领域。概述了 CLIP、OpenCLIP、扩散模型、DALL-E-2 模型、Stable Diffusion 模型等文生图(Text…...
03.从简单的sql开始
从简单的sql开始 一、sql语句的种类二、oracle的工作原理三、oracle数据库常见基础命令 一、sql语句的种类 下面是SQL语句的分类、常用语句、使用方法: 分类语句使用方法解释数据查询SELECTSELECT column1, column2, … FROM table_name WHERE condition;用于从表…...
JS加密/解密之jsjiami在线js加密的效率问题
故事背景 经常有客户反馈,v7加密的效率比v6低,但是安全性更好。这里我给大家科普一下关于jsjiami的优化诀窍。 示例源代码 // 伪代码 while (1) {var name ‘张三’ }优化后 var _name 张三; while (1) {var name _name }优化原理 相信很多朋…...
解决【spring boot】Process finished with exit code 0的问题
文章目录 1. 复现错误2. 分析错误3. 解决问题 1. 复现错误 今天从https://start.spring.io下载配置好的spring boot项目: 启动后却报出如下错误: 即Process finished with exit code 0 2. 分析错误 Process finished with exit code 0翻译成中文进程已完…...
模电学习路径
交流通路实质 列出电路方程1,方程1对时刻t做微分 所得方程1‘ 即为 交流通路 方程1对时刻t做微分:两个不同时刻的方程1相减,并 令两时刻差为 无穷小 微分 改成 差 模电学习路径: 理论 《电路原理》清华大学 于歆杰 朱桂萍 陆文…...
【Linux】配置JDKTomcat开发环境及MySQL安装和后端项目部署
目录 一、jdk安装配置 1. 传入资源 2. 解压 3. 配置 二、Tomcat安装 1. 解压开启 2. 开放端口 三、MySQL安装 1. 解压安装 2. 登入配置 四、后端部署 1. 数据库 2. 导入.war包 3. 修改端口 4.开启访问 一、jdk安装配置 打开虚拟机 Centos 登入账号ÿ…...
Modelsim 使用教程(3)——Projects
目录 一、概述 二、设计文件及tb 2.1 设计文件 counter.v 2.2 仿真文件 tcounter.v 三、操作流程 3.1 Create a New Project(创建一个新的工程) 3.2 Add Objects to the Project(把代码加入项目) 3.3 Compile the …...
Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...
【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...
uniapp 字符包含的相关方法
在uniapp中,如果你想检查一个字符串是否包含另一个子字符串,你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的,但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...
android13 app的触摸问题定位分析流程
一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...
【Linux系统】Linux环境变量:系统配置的隐形指挥官
。# Linux系列 文章目录 前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变量的生命周期 四、环境变量的组织方式五、C语言对环境变量的操作5.1 设置环境变量:setenv5.2 删除环境变量:unsetenv5.3 遍历所有环境…...
安卓基础(Java 和 Gradle 版本)
1. 设置项目的 JDK 版本 方法1:通过 Project Structure File → Project Structure... (或按 CtrlAltShiftS) 左侧选择 SDK Location 在 Gradle Settings 部分,设置 Gradle JDK 方法2:通过 Settings File → Settings... (或 CtrlAltS)…...
Docker拉取MySQL后数据库连接失败的解决方案
在使用Docker部署MySQL时,拉取并启动容器后,有时可能会遇到数据库连接失败的问题。这种问题可能由多种原因导致,包括配置错误、网络设置问题、权限问题等。本文将分析可能的原因,并提供解决方案。 一、确认MySQL容器的运行状态 …...
FFmpeg avformat_open_input函数分析
函数内部的总体流程如下: avformat_open_input 精简后的代码如下: int avformat_open_input(AVFormatContext **ps, const char *filename,ff_const59 AVInputFormat *fmt, AVDictionary **options) {AVFormatContext *s *ps;int i, ret 0;AVDictio…...
