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

[React]useMemoizedFn和useCallback对比

useMemoizedFn文档地址:https://ahooks.js.org/zh-CN/hooks/use-memoized-fn

hooks组件内什么时候会更新自定义函数

在 React 中,自定义的 Hooks 内部的函数在以下常见的几种情况下会被重新赋值,导致更新引用:

  • 组件重新渲染:

    当组件重新渲染时,Hooks 内部的函数会被重新执行,从而导致函数的重新赋值和更新引用。
    这意味着每次组件重新渲染时,Hooks 内部的函数会被重新计算,返回新的函数引用。

  • 依赖项发生变化(对于使用了依赖项的 Hooks):

    对于某些 Hooks,例如 useEffect、useMemo 和 useCallback,当其依赖项发生变化时,Hooks 内部的函数也会被重新执行。
    这会导致函数的重新赋值和更新引用,以确保在依赖项发生变化时能够获得最新的函数引用。

  • 闭包内部依赖的状态发生变化:

    自定义的 Hooks 可能使用闭包内部的状态或其他上下文中的值作为依赖,如果这些依赖的状态发生变化,Hooks 内部的函数也会重新执行。这样做是为了保持函数内部依赖的状态是最新的,避免出现闭包中使用过期数据的问题。

useCallback和useMemoizedFn对比

在 React 中,useMemoizedFnuseCallback 都用于优化函数组件的性能,但它们有一些不同点。

  1. 目的:
    • useMemoizedFn: 这不是 React 的内置 Hook,而是可能由第三方库提供的功能。它的目的是将一个函数 “记忆化”,类似于 useCallback,但在某些情况下,它提供了更多的功能,例如支持自定义的缓存策略和多个实例之间共享缓存等。
    • useCallback: 这是 React 的内置 Hook,专门用于记忆化函数。它的主要目的是在依赖项列表不变时,返回相同的函数引用,以减少函数的重新创建。
  2. 用法:
    • useMemoizedFn 的基本思想是将一个函数包装起来,并根据特定的条件缓存函数的结果,以便在相同的输入参数下再次调用时,直接返回缓存的结果,而不必重新计算。
    • useCallback 接受一个函数和依赖项列表,并在依赖项列表不变时返回记忆化的函数引用。
import React, { useState, useCallback } from 'react';
import { message } from 'antd';
import { useMemoizedFn } from 'ahooks';export default () => {const [count, setCount] = useState(0);const callbackFn = useCallback(() => {message.info(`Current count is ${count}`);}, [count]);const memoizedFn = useMemoizedFn(() => {message.info(`Current count is ${count}`);});return (<><p>count: {count}</p><buttontype="button"onClick={() => {setCount((c) => c + 1);}}>Add Count</button><div style={{ marginTop: 16 }}><button type="button" onClick={callbackFn}>call callbackFn</button><button type="button" onClick={memoizedFn} style={{ marginLeft: 8 }}>call memoizedFn</button></div></>);
};

在上面的示例中,callbackFn和memoizedFn效果是一样的,区别在于memoizedFn不用自己指定依赖。

useCallback:使用useMemo实现

使用 useMemo 来实现类似于 useCallback 的功能。事实上,useCallback 本质上就是使用 useMemo 来进行函数记忆化的一种简化形式。

useCallbackuseMemo 都是 React 的内置 Hook,它们都用于在依赖项不变时,返回记忆化的值。唯一的区别是 useCallback 是专门用于记忆化函数,而 useMemo 可以用于任何类型的值。

在 React 组件中,当函数作为依赖项传递给子组件时,通常会使用 useCallback 来确保子组件不会因为父组件的重新渲染而频繁地创建新的函数。然而,你也可以使用 useMemo 来达到相同的目的。

下面是一个使用 useMemo 实现类似于 useCallback 的示例:

import React, { useState, useMemo } from 'react';function useMyCallback(callback, deps) {return useMemo(() => callback, deps);
}const MyComponent = () => {const [count, setCount] = useState(0);// 使用 useMyCallback 记忆化函数const handleClick = useMyCallback(() => {console.log('Callback function called');setCount(count + 1);}, [count]);return (<div><p>Count: {count}</p><button onClick={handleClick}>Increment</button></div>);
};

在上面的示例中,我们定义了一个 useMyCallback Hook,它接受一个函数 callback 和一个依赖项列表 deps。在内部,我们使用 useMemo 将传入的 callback 进行记忆化,并返回记忆化的函数引用。

这样,当 count 不变时,handleClick 将返回相同的函数引用,避免了因为父组件重新渲染而导致的函数的频繁创建,从而实现了和 useCallback 类似的功能。

useMemoizedFn:使用useMemo实现

useMemoizedFn 是持久化 function 的 Hook,理论上,可以使用 useMemoizedFn 完全代替 useCallback。使用 useMemoizedFn,可以省略第二个参数 deps,同时保证函数地址永远不会变化

function useMemoizedFn(func){if(typeof func !== 'function') return// 通过 useRef 保持其引用地址不变,并且值能够保持值最新const funcRef = useRef(func)funcRef.current = useMemo(()=>{return func}, [func])const memoizedFn = useRef();if (!memoizedFn.current) {// 返回的持久化函数,调用该函数的时候,调用原始的函数memoizedFn.current = function(...args){return funcRef.current.apply(this, args)}}return memoizedFn.current
}

ahooks源码实现如下:

import { useMemo, useRef } from 'react';
import { isFunction } from '../utils';
import isDev from '../utils/isDev';
function useMemoizedFn(fn) {if (isDev) {if (!isFunction(fn)) {console.error("useMemoizedFn expected parameter is a function, got ".concat(typeof fn));}}var fnRef = useRef(fn);// why not write `fnRef.current = fn`?// https://github.com/alibaba/hooks/issues/728fnRef.current = useMemo(function () {return fn;}, [fn]);var memoizedFn = useRef();if (!memoizedFn.current) {memoizedFn.current = function () {var args = [];for (var _i = 0; _i < arguments.length; _i++) {args[_i] = arguments[_i];}return fnRef.current.apply(this, args);};}return memoizedFn.current;
}
export default useMemoizedFn;

useMemoizedFn 的实现中使用了两个 useRef 钩子,具有不同的用途:

  1. fnRef:这个 useRef 用于存储原始函数(fn)的引用。它被初始化为传递给 useMemoizedFn 函数的 fn 参数,并且其目的是始终保持函数的最新版本。使用它的原因是确保记忆化的函数(memoizedFn)能够始终调用最新版本的原始函数 fn,即使在渲染之间 fn 发生了变化。

  2. memoizedFn:这个 useRef 用于存储将由 useMemoizedFn 钩子返回的记忆化函数。其目的是在渲染间保持记忆化函数的引用。当 memoizedFn 首次创建时,它被赋值为一个新的函数,该函数调用最新版本的 fnRef.current 并传递提供的参数。然后,这个记忆化函数被返回并在组件中使用。

这样的实现通过使用两个独立的 useRef 钩子,确保记忆化函数能够正确地引用最新版本的原始函数,同时保持记忆化函数本身的稳定引用。

使用 useMemo 更新 fnRef.current 而不是直接赋值 fnRef.current = fn,是为了确保当 fn 依赖项发生变化时,记忆化函数会被重新计算。通过在 useMemo 中使用 [fn] 作为依赖项数组,记忆化函数将始终引用 fn 的最新版本,并在 fn 发生变化时相应地更新。

这个实现旨在确保 useMemoizedFn 返回的记忆化函数保持高效,并正确地反映原始函数的最新版本和其依赖项的最新变化。

参考文章

https://juejin.cn/post/7106061970184339464#heading-6

https://ahooks.js.org/zh-CN/hooks/use-memoized-fn

相关文章:

[React]useMemoizedFn和useCallback对比

useMemoizedFn文档地址&#xff1a;https://ahooks.js.org/zh-CN/hooks/use-memoized-fn hooks组件内什么时候会更新自定义函数 在 React 中&#xff0c;自定义的 Hooks 内部的函数在以下常见的几种情况下会被重新赋值&#xff0c;导致更新引用&#xff1a; 组件重新渲染&…...

计算机毕设 深度学习人体跌倒检测 -yolo 机器视觉 opencv python

文章目录 0 前言1.前言2.实现效果3.相关技术原理3.1卷积神经网络3.1YOLOV5简介3.2 YOLOv5s 模型算法流程和原理4.数据集处理3.1 数据标注简介3.2 数据保存 5.模型训练 6 最后 0 前言 &#x1f525; 这两年开始毕业设计和毕业答辩的要求和难度不断提升&#xff0c;传统的毕设题…...

完全背包

动态规划解题步骤 : 动态规划问题一般从三个步骤进行考虑。 步骤一:集合和集合的状态 所谓的集合&#xff0c;就是一些方案的集合。 用 g[i][j] 表示从前 i 种物品中进行选择&#xff0c;且总体积不大于 j 的各个选法获得的价值的集合。注意&#xff1a;g[i][j] 不是一个数…...

【软件测试】webdriver常用API演示(Java+IDEA+chrome浏览器)

1.元素定位方法 对象的定位应该是自动化测试的核心&#xff0c;要想操作一个对象&#xff0c;首先应该识别这个对象。一个对象就是一个人一样&#xff0c;他会有各种的特征&#xff08;属性&#xff09;&#xff0c;如比我们可以通过一个人的身份证号&#xff0c;姓名&#xf…...

Linux安装MySQL 8.1.0

MySQL是一个流行的开源关系型数据库管理系统&#xff0c;本教程将向您展示如何在Linux系统上安装MySQL 8.1.0版本。请按照以下步骤进行操作&#xff1a; 1. 下载MySQL安装包 首先&#xff0c;从MySQL官方网站或镜像站点下载MySQL 8.1.0的压缩包mysql-8.1.0-linux-glibc2.28-x…...

多线程面试相关的一些问题

面试题 1. 常见的锁策略相关的面试题 2. CAS相关的面试题 3. Synchronized 原理相关的面试题 4. Callable 接口相关的面试题 1. 常见的锁策略 乐观锁 vs 悲观锁 悲观锁: 总是假设最坏的情况&#xff0c;每次去拿数据的时候都认为别人会修改&#xff0c;所以每次在拿数据的时候都…...

【使用维纳滤波进行信号分离】基于维纳-霍普夫方程的信号分离或去噪维纳滤波器估计(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

Vue+axios如何解决跨域

1、为什么会产生跨域&#xff1f; 出于浏览器的同源策略限制。 同源策略&#xff08;Sameoriginpolicy&#xff09;是一种约定&#xff0c;是浏览器的一种安全机…...

网络安全系统中的守护者:如何借助威胁情报 (TI) 提高安全性

在这篇哈巴尔网站上的推文中&#xff0c;我们将解释 TI 缩写背后的含义、为什么需要它、Positive Technologies 收集哪些网络威胁数据以及如何帮助企业预防网络威胁。我们将以四种情况为例&#xff0c;说明公司如何使用 PT Threat Intelligence Feeds 来发现恶意活动并预防攻击…...

并发编程 - CompletableFuture

文章目录 Pre概述FutureFuture的缺陷类继承关系功能概述API提交任务的相关API结果转换的相关APIthenApplyhandlethenRunthenAcceptthenAcceptBoththenCombinethenCompose 回调方法的相关API异常处理的相关API获取结果的相关API DEMO实战注意事项 Pre 每日一博 - Java 异步编程…...

IPIDEA参展ChinaJoy!探索未来创新科技的峰会之旅

中国最大的国际数码互动娱乐展会ChinaJoy即将于7月28日在上海举行&#xff0c;届时将聚集全球来自22个国家和地区的领先科技公司、创业者和技术专家&#xff0c;为参观者呈现一系列引人入胜的展览和活动。而IPIDEA作为参展商之一&#xff0c;将为参观者带来一场关于数字科技的奇…...

2023最新ChatGPT商业运营版网站源码+支持ChatGPT4.0+GPT联网+支持ai绘画(Midjourney)+支持Mind思维导图生成

本系统使用Nestjs和Vue3框架技术&#xff0c;持续集成AI能力到本系统&#xff01; 支持GPT3模型、GPT4模型Midjourney专业绘画&#xff08;全自定义调参&#xff09;、Midjourney以图生图、Dall-E2绘画Mind思维导图生成应用工作台&#xff08;Prompt&#xff09;AI绘画广场自定…...

轮趣科技教育版ros小车键盘控制运动

我之前买的ros小车是单独买的底板&#xff0c;以为随便一个树莓派就可以&#xff0c;因为我以前有一个树莓派3B&#xff0c;后来买了单独的小车之后&#xff0c;发现只能使用树莓派4B&#xff0c;然后又单独买了一个树莓派4B&#xff0c;给装上镜像&#xff0c;安装ros-melodic…...

深入理解Python中的os.chdir()方法

深入理解Python中的os.chdir()方法 1. 简介 在Python中&#xff0c;os.chdir()方法用于改变当前的工作目录。工作目录是指当前正在执行的脚本所在的目录。通过使用os.chdir()方法&#xff0c;我们可以在脚本执行过程中切换到不同的目录。 在编写Python脚本时&#xff0c;我们…...

【Golang 接口自动化02】使用标准库net/http发送Post请求

目录 写在前面 发送Post请求 示例代码 源码分析 Post请求参数解析 响应数据解析 验证 发送Json/XMl Json请求示例代码 xml请求示例代码 总结 资料获取方法 写在前面 上一篇我们介绍了使用 net/http 发送get请求&#xff0c;因为考虑到篇幅问题&#xff0c;把Post单…...

LaTex语法(常用数学符号的语法和注意事项)

说明:[]括号表示把语法括起来&#xff0c;并不表示LaTex语法。 1. 求和符号(Σ) 这个符号的基本语法为&#xff1a;[\sum_{}^{}]。 符号有两种模式&#xff1a;内联数学模式(inside math mode)和显示数学模式(displayed math mode)。 内联数学模式&#xff1a;排版时使用各…...

Yunfly 一款高效、性能优异的node.js企业级web框架

介绍 Yunfly 一款高性能 Node.js WEB 框架, 使用 Typescript 构建我们的应用。 使用 Koa2 做为 HTTP 底层框架, 使用 routing-controllers 、 typedi 来高效构建我们的 Node 应用。 Yunfly 在 Koa 框架之上提升了一个抽象级别, 但仍然支持 Koa 中间件。在此基础之上, 提供了一…...

mac m1安装Centos9

先看结果&#xff08;在mac M1 安装centos8 安装不成功的原因大部分是没有找到正确的系统&#xff09; 由于Cnetos8 停服&#xff0c;现有mac m1 上能够按照的Centos8 并非由官方发布&#xff0c;因此寻找官方发布的能够在mac m1上安装的centos版本。 在YouTuBe上找到一个视频…...

深入理解mAP

0 介绍 mAP是目标检测任务最重要的评价指标。 mAP 是mean average precosion的缩写&#xff0c;mean 和 average都是平均的意思&#xff0c; 所以这个指标的计算涉及到2次平均。 mean是对所有类别的平均&#xff0c; 比如VOC 数据有20个类&#xff0c; 每个类别分别计算AP&…...

PostGis -基础、Springboot 整合、电子围栏处理

目的&#xff1a; 为什么要用PostgreSQL? 因为有时候我们需要存储 空间数据&#xff0c;如&#xff1a;存储一个 多边形 到数据。PostGis中 geometry、geography &#xff1a;基本空间数据类型&#xff0c;用于表达点线面等空间要素&#xff0c;具体类型涵盖了OGC的简单对象模…...

SpringBoot的java应用中,慢sql会导致CPU暴增吗

是的&#xff0c;在 Spring Boot 的 Java 应用中&#xff0c;慢 SQL 同样可能导致 CPU 暴增。虽然数据库服务器的 CPU 通常是主要压力点&#xff0c;但应用服务器&#xff08;Java 进程&#xff09;的 CPU 也可能间接受到影响&#xff0c;具体原因和机制如下&#xff1a; 1. 数…...

word批量导出visio图

具体步骤 修改word格式打开VBA窗口插入代码运行代码 修改word格式 将word文档修改为docm格式 打开VBA窗口 打开开发工具VisualBasic项&#xff0c;如果没有右键在自定义功能区添加 插入代码 插入 -> 模块&#xff0c;代码如下&#xff1a; Sub ExportAllVisioDiagrams()D…...

(LeetCode 每日一题) 909. 蛇梯棋 (广度优先搜索bfs)

题目&#xff1a;909. 蛇梯棋 思路&#xff1a;广度优先搜索bfs队列&#xff0c;时间复杂度0(6*n^2)。 细节看注释 C版本&#xff1a; class Solution { public:int snakesAndLadders(vector<vector<int>>& board) {int nboard.size();// vis[i]&#xff1a;…...

工业控制核心引擎高性能MCU——MM32F5370

RAMSUN提供的MM32F5370搭载180MHz Arm China Star-MC1处理器&#xff0c;集成DSP、FPU与三角函数加速单元&#xff08;CORDIC&#xff09;&#xff0c;轻松应对复杂算法需求。其技术亮点包括&#xff1a; 超高精度PWM&#xff1a;8通道208ps级高精度PWM输出&#xff0c;满足储能…...

uniapp使用Canvas生成电子名片

uniapp使用Canvas生成电子名片 工作中有生成电子名片的一个需求&#xff0c;刚刚好弄了发一下分享分享 文章目录 uniapp使用Canvas生成电子名片前言一、上代码&#xff1f;总结 前言 先看效果 一、上代码&#xff1f; 不对不对应该是上才艺&#xff0c;哈哈哈 <template…...

声纹技术体系:从理论基础到工程实践的完整技术架构

文章目录 一、声纹技术的理论基础与概念内核1.1 声纹的生物学本质与数学表征1.2 特征提取的理论基础与实现机制 二、声纹识别技术的演进逻辑与方法体系2.1 传统统计学方法的理论架构2.2 深度学习方法的技术革新2.3 损失函数的设计原理与优化策略 三、声纹识别系统的架构设计与模…...

JVM——回顾:JVM的起源、特性与系统构成

引入 在当今数字化时代&#xff0c;Java语言及其运行环境Java虚拟机&#xff08;JVM&#xff09;在软件开发领域占据着举足轻重的地位。从大型企业级应用到各类移动应用&#xff0c;JVM凭借其独特的特性和强大的功能&#xff0c;为开发者提供了高效且稳定的运行环境。 JVM的起…...

从0到1上手Trae:开启AI编程新时代

摘要&#xff1a;字节跳动 2025 年 1 月 19 日发布的 Trae 是一款 AI 原生集成开发环境工具&#xff0c;3 月 3 日国内版推出。它具备 AI 问答、代码自动补全、基于 Agent 编程等功能&#xff0c;能自动化开发任务&#xff0c;实现端到端开发。核心功能包括智能代码生成与补全、…...

STM32G4 电机外设篇(一) GPIO+UART

目录 一、STM32G4 电机外设篇&#xff08;一&#xff09; GPIOUART1 GPIO1.1 STM32CUBEMX 配置以及Keil代码1.2 代码和实验现象 2 UART2.1 STM32CUBEMX 配置以及Keil代码2.2 代码和实验现象 附学习参考网址欢迎大家有问题评论交流 (* ^ ω ^) 一、STM32G4 电机外设篇&#xff0…...

如何成为一名优秀的产品经理

一、 夯实核心基础 深入理解智能驾驶技术栈&#xff1a; 感知&#xff1a; 摄像头、雷达&#xff08;毫米波、激光雷达&#xff09;、超声波传感器的工作原理、优缺点、融合策略。了解目标检测、跟踪、SLAM等基础算法概念。 定位&#xff1a; GNSS、IMU、高精地图、轮速计等定…...