当前位置: 首页 > 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的简单对象模…...

2026特级防火卷帘门价格明细、国标参数及选购避坑指南(河北厂家实测)

在商业综合体、地下车库、厂房消防验收场景中&#xff0c;特级防火卷帘门是核心防火分隔设备&#xff0c;因具备3小时极限耐火极限&#xff0c;成为大型建筑消防报审的刚需产品。很多工程采购、消防从业者在选型时&#xff0c;容易混淆普通卷帘与特级卷帘的区别&#xff0c;同时…...

2026年京东云OpenClaw/Hermes Agent配置Token Plan安装详细指南

2026年京东云OpenClaw/Hermes Agent配置Token Plan安装详细指南。OpenClaw是开源的个人AI助手&#xff0c;Hermes Agent则是一个能自我进化的AI智能体框架。阿里云提供计算巢、轻量服务器及无影云电脑三种部署OpenClaw 与 Hermes Agent的方案、百炼Token Plan兼容主流 AI 工具&…...

C++类型推导与auto关键字

C类型推导与auto关键字 类型推导是C11引入的重要特性&#xff0c;通过auto和decltype关键字&#xff0c;编译器可以自动推导变量的类型&#xff0c;减少代码冗余并提高可维护性。 auto关键字让编译器根据初始化表达式推导变量类型。 #include #include #include #include v…...

微软逐步淘汰 SMS 身份验证,通行密钥带来更强安全保障!

ZDNET 要点总结微软正在逐步淘汰将 SMS 作为身份验证方式&#xff0c;因为 SMS 消息未加密&#xff0c;易受黑客攻击。微软账户所有者将被提示设置通行密钥。通常登录或找回在线账户时会收到 SMS 验证短信&#xff0c;但这并非安全的身份验证方式&#xff0c;如今微软对使用微软…...

魔兽争霸III终极优化指南:5大功能彻底解决现代系统兼容性问题

魔兽争霸III终极优化指南&#xff1a;5大功能彻底解决现代系统兼容性问题 【免费下载链接】WarcraftHelper Warcraft III Helper , support 1.20e, 1.24e, 1.26a, 1.27a, 1.27b 项目地址: https://gitcode.com/gh_mirrors/wa/WarcraftHelper 还在为魔兽争霸III在现代电脑…...

首次购买Token Plan套餐,在真实项目中的成本控制效果初探

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 首次购买Token Plan套餐&#xff0c;在真实项目中的成本控制效果初探 1. 项目背景与成本考量 作为一名独立开发者&#xff0c;我最…...

Photoshop到URP的法线验证闭环:跨引擎法线贴图精准调试指南

1. 这不是个“一键生成法线”的玩具&#xff0c;而是一套跨引擎、跨工作流的材质验证闭环你有没有遇到过这样的情况&#xff1a;在 Photoshop 里辛苦调出一张完美的 Normal Map&#xff0c;导入 Unity 后却发现高光方向反了、边缘发灰、贴图在 Decal 上拉伸变形&#xff0c;甚至…...

Android Studio中文界面快速配置指南:5分钟告别英文开发困扰

Android Studio中文界面快速配置指南&#xff1a;5分钟告别英文开发困扰 【免费下载链接】AndroidStudioChineseLanguagePack AndroidStudio中文插件(官方修改版本&#xff09; 项目地址: https://gitcode.com/gh_mirrors/an/AndroidStudioChineseLanguagePack 还在为An…...

【Coze工作流】零代码做AI自动化,小白也能5分钟上手

一、问题背景&#xff1a;手工做重复AI任务太累&#xff0c;想自动化但不会写代码在日常办公或者内容创作中&#xff0c;很多人都有过这样的痛点&#xff1a;每天要重复打开各种AI工具。比如你要写一篇爆款文章&#xff0c;先要找AI找选题&#xff0c;再让AI写大纲&#xff0c;…...

如何利用碎片时间高效背单词:ToastFish桌面工具完整使用教程

如何利用碎片时间高效背单词&#xff1a;ToastFish桌面工具完整使用教程 【免费下载链接】ToastFish 一个利用摸鱼时间背单词的软件。 项目地址: https://gitcode.com/GitHub_Trending/to/ToastFish 想要在工作或学习间隙轻松记忆单词&#xff0c;却苦于没有专门的学习时…...