React 中useMemo和useCallback Hook 的作用,在什么场景下使用它们?
大白话React 中useMemo和useCallback Hook 的作用,在什么场景下使用它们?
在 React 里,useMemo 和 useCallback 这两个 Hook 可有用啦,能帮咱优化组件性能,避免不必要的计算和渲染。下面咱就来详细聊聊它们的作用和使用场景。
useMemo
useMemo 就像是一个缓存小能手,它会记住某个计算结果,下次再遇到相同的输入时,就直接拿出之前算好的结果,而不用重新计算,这样能节省不少性能。
咱来看个简单的例子:
import React, { useMemo, useState } from 'react';// 定义一个组件
const ExampleComponent = () => {// 定义一个状态,用于控制是否更新const [count, setCount] = useState(0);// 使用 useMemo 来缓存一个复杂计算的结果const expensiveValue = useMemo(() => {// 模拟一个复杂的计算console.log('进行复杂计算...');let sum = 0;for (let i = 0; i < 1000000; i++) {sum += i;}return sum;}, []); // 依赖项数组为空,意味着只计算一次return (<div><p>计数: {count}</p>{/* 显示复杂计算的结果 */}<p>复杂计算结果: {expensiveValue}</p><button onClick={() => setCount(count + 1)}>增加计数</button></div>);
};export default ExampleComponent;
代码解释:
useMemo接收两个参数,第一个参数是一个函数,这个函数里放着要进行的复杂计算;第二个参数是一个依赖项数组。- 当依赖项数组为空时,
useMemo里的函数只会在组件第一次渲染时执行,之后就直接用缓存的结果。 - 要是依赖项数组里有值,那只要这些值有变化,
useMemo里的函数就会重新执行。
使用场景:
- 当有复杂的计算,而且这个计算的输入在一段时间内不会变时,就可以用
useMemo把结果缓存起来,避免每次渲染都重新计算。 - 当传递给子组件的对象或数组,每次渲染时引用都不同,导致子组件不必要的重新渲染时,也可以用
useMemo来保持引用不变。
useCallback
useCallback 和 useMemo 有点像,但它主要是用来缓存函数的。在 React 里,每次组件重新渲染时,函数都会重新创建,这可能会导致一些问题,比如子组件不必要的重新渲染。useCallback 就能解决这个问题,它会记住函数的引用,只要依赖项不变,函数的引用就不会变。
看个例子:
import React, { useCallback, useState } from 'react';// 定义一个子组件
const ChildComponent = ({ onClick }) => {console.log('子组件渲染');return (<button onClick={onClick}>点击我</button>);
};// 定义一个父组件
const ParentComponent = () => {// 定义一个状态,用于控制是否更新const [count, setCount] = useState(0);// 使用 useCallback 来缓存一个函数const handleClick = useCallback(() => {console.log('按钮被点击了');setCount(count + 1);}, [count]); // 依赖项数组包含 countreturn (<div><p>计数: {count}</p>{/* 传递缓存的函数给子组件 */}<ChildComponent onClick={handleClick} /></div>);
};export default ParentComponent;
代码解释:
useCallback也接收两个参数,第一个参数是要缓存的函数,第二个参数是依赖项数组。- 只要依赖项数组里的值不变,
useCallback返回的函数引用就不会变。
使用场景:
- 当把函数作为 props 传递给子组件时,用
useCallback可以避免子组件因为函数引用的变化而不必要的重新渲染。 - 当函数是作为依赖项传递给其他 Hook(比如
useEffect)时,用useCallback可以保证函数引用的稳定性。
总的来说,useMemo 主要用于缓存计算结果,useCallback 主要用于缓存函数,合理使用它们能让 React 应用的性能更上一层楼!
除了性能优化,useMemo和useCallback还有哪些应用场景?
除了性能优化外,useMemo 和 useCallback 在 React 开发中还有其他一些实用的应用场景,下面分别介绍:
useMemo 的其他应用场景
1. 确保对象引用的一致性
在 React 中,有些组件可能依赖于某个对象,如果每次渲染时该对象的引用都发生变化,可能会导致不必要的重新渲染。使用 useMemo 可以确保对象引用的一致性,只有当依赖项发生变化时,对象才会被重新创建。
import React, { useMemo, useState } from 'react';const Example = () => {const [count, setCount] = useState(0);// 使用 useMemo 确保 options 对象引用的一致性const options = useMemo(() => ({label: '选项',value: count}), [count]);return (<div><p>Count: {count}</p><button onClick={() => setCount(count + 1)}>Increment</button></div>);
};export default Example;
2. 条件渲染中的计算
当需要根据某些条件进行复杂的计算以决定是否渲染某个组件时,useMemo 可以帮助缓存计算结果,避免每次渲染都进行重复计算。
import React, { useMemo, useState } from 'react';const Example = () => {const [isLargeNumber, setIsLargeNumber] = useState(false);const [number, setNumber] = useState(0);// 使用 useMemo 缓存计算结果const shouldShowMessage = useMemo(() => {return number > 100;}, [number]);return (<div><inputtype="number"value={number}onChange={(e) => setNumber(Number(e.target.value))}/>{shouldShowMessage && <p>数字大于 100</p>}</div>);
};export default Example;
useCallback 的其他应用场景
1. 事件处理函数的传递
在高阶组件或自定义 Hook 中,当需要将事件处理函数作为参数传递时,使用 useCallback 可以确保传递的函数引用保持不变,避免不必要的重新渲染。
import React, { useCallback, useState } from 'react';// 自定义 Hook
const useCounter = () => {const [count, setCount] = useState(0);// 使用 useCallback 缓存 increment 函数const increment = useCallback(() => {setCount(count + 1);}, [count]);return { count, increment };
};const Example = () => {const { count, increment } = useCounter();return (<div><p>Count: {count}</p><button onClick={increment}>Increment</button></div>);
};export default Example;
2. 避免无限循环
在某些情况下,如果不使用 useCallback,可能会导致无限循环。例如,在 useEffect 中依赖一个函数,如果该函数每次渲染都重新创建,就会触发 useEffect 不断执行。使用 useCallback 可以避免这种情况。
import React, { useCallback, useEffect, useState } from 'react';const Example = () => {const [count, setCount] = useState(0);// 使用 useCallback 缓存函数const fetchData = useCallback(() => {// 模拟数据获取console.log('Fetching data...');}, []);useEffect(() => {fetchData();}, [fetchData]);return (<div><p>Count: {count}</p><button onClick={() => setCount(count + 1)}>Increment</button></div>);
};export default Example;
这些场景展示了 useMemo 和 useCallback 在除性能优化之外的其他用途,它们可以帮助开发者更好地管理组件的状态和行为。
React 中useMemo和useCallback Hook 的优缺点以及区别?
优点
useMemo
- 性能优化:能对复杂计算结果进行缓存,避免每次渲染都重新计算。比如在处理大数据集的排序、过滤等复杂操作时,使用
useMemo可显著提升性能。 - 稳定引用:保证对象、数组等引用类型在依赖项未改变时引用不变,避免因引用变化导致子组件不必要的重新渲染。
useCallback
- 性能优化:缓存函数,避免函数在每次渲染时重新创建,从而减少不必要的内存分配和垃圾回收,优化性能。
- 稳定函数引用:当把函数作为 props 传递给子组件时,使用
useCallback可保证函数引用稳定,防止子组件因函数引用变化而重新渲染。
缺点
useMemo
- 增加内存开销:由于需要缓存计算结果,会占用一定的内存空间。如果缓存的数据量较大,可能会对内存造成压力。
- 过度使用导致代码复杂:若过度使用
useMemo,会使代码逻辑变得复杂,增加维护难度。而且不合理地设置依赖项,可能会导致缓存结果不准确。
useCallback
- 增加复杂性:和
useMemo类似,过度使用会让代码逻辑变得复杂,尤其是依赖项较多时,难以理解和维护。 - 依赖项管理困难:需要正确设置依赖项,若依赖项设置不当,可能导致函数不能及时更新,出现逻辑错误。
区别
功能用途
- useMemo:主要用于缓存计算结果,返回的是计算结果的值。适合缓存复杂计算、数据转换等操作的结果。
- useCallback:主要用于缓存函数,返回的是一个函数。常用于将函数作为 props 传递给子组件,确保函数引用的稳定性。
语法形式
- useMemo:接收两个参数,第一个参数是一个函数,该函数返回需要缓存的值;第二个参数是一个依赖项数组。示例如下:
const memoizedValue = useMemo(() => {// 进行复杂计算return someComputation();
}, [dependency1, dependency2]);
- useCallback:同样接收两个参数,第一个参数是要缓存的函数,第二个参数是依赖项数组。示例如下:
const memoizedCallback = useCallback(() => {// 函数逻辑doSomething();
}, [dependency1, dependency2]);
返回值
- useMemo:返回的是第一个参数函数的返回值。
- useCallback:返回的是第一个参数传入的函数本身。
通过下面的示例能更直观地看出它们的区别:
import React, { useMemo, useCallback, useState } from 'react';const ParentComponent = () => {const [count, setCount] = useState(0);// 使用 useMemo 缓存计算结果const memoizedValue = useMemo(() => {console.log('Calculating memoized value...');return count * 2;}, [count]);// 使用 useCallback 缓存函数const memoizedCallback = useCallback(() => {console.log('Button clicked!');setCount(count + 1);}, [count]);return (<div><p>Count: {count}</p><p>Memoized Value: {memoizedValue}</p><button onClick={memoizedCallback}>Increment</button></div>);
};export default ParentComponent;
在这个示例中,useMemo 缓存了 count * 2 的计算结果,useCallback 缓存了 increment 函数。
相关文章:
React 中useMemo和useCallback Hook 的作用,在什么场景下使用它们?
大白话React 中useMemo和useCallback Hook 的作用,在什么场景下使用它们? 在 React 里,useMemo 和 useCallback 这两个 Hook 可有用啦,能帮咱优化组件性能,避免不必要的计算和渲染。下面咱就来详细聊聊它们的作用和使…...
Android笔记之项目引用第三方库(如:Github等)
前言:原生Android开发时引用github上的仓库内容,故出此文。 方式一:使用 JitPack(推荐) 步骤 1:在项目的 build.gradle 文件中添加 JitPack 仓库 打开项目根目录下的 build.gradle 文件,在 a…...
Linux 系统性能优化高级全流程指南
Linux 系统性能优化高级全流程指南 一、系统基础状态捕获 1. 系统信息建档 除了原有的硬件、内核和存储拓扑信息收集,还增加 CPU 缓存、网络设备详细信息等。 # 硬件信息 lscpu > /opt/tuning/lscpu.origin dmidecode -t memory > /opt/tuning/meminfo.or…...
SQL Server——表数据的插入、修改和删除
目录 一、引言 二、表数据的插入、修改和删除 (一)方法一:在SSMS控制台上进行操作 1.向表中添加数据 2.对表中的数据进行修改 3.对表中的数据进行删除 (二)方法二:使用 SQL 代码进行操作 1.向表中添…...
WPF 布局中的共性尺寸组(Shared Size Group)
1. 什么是共性尺寸组? 在 WPF 的 Grid 布局中,SharedSizeGroup 允许多个 Grid 共享同一列或行的尺寸,即使它们属于不同的 Grid 也能保持大小一致。这样可以保证界面元素的对齐性,提高布局的一致性。 SharedSizeGroup 主要用于需…...
deepSeek-SSE流式推送数据
1、背景 DeepSeek作为当前最火的AI大模型, 使用的时候用户在输入框输入问题,大模型进行思考回答你,然后会有一个逐步显示的过程效果,而不是一次性返回整个答案给前端页面进行展示,为了搞清楚其中的原理,我们…...
【北京迅为】iTOP-RK3568开发板OpenHarmony系统南向驱动开发UART接口运作机制
瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码,支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU,可用于轻量级人工…...
Leetcode 3495. Minimum Operations to Make Array Elements Zero
Leetcode 3495. Minimum Operations to Make Array Elements Zero 1. 解题思路2. 代码实现 题目链接:3495. Minimum Operations to Make Array Elements Zero 1. 解题思路 这一题的话核心就是统计对任意自然数 n n n,从 1 1 1到 n n n当中所有的数字对…...
C#实现自己的Json解析器(LALR(1)+miniDFA)
C#实现自己的Json解析器(LALR(1)miniDFA) Json是一个用处广泛、文法简单的数据格式。本文介绍如何用bitParser(拥有自己的解析器(C#实现LALR(1)语法解析器和miniDFA词法分析器的生成器)迅速实现一个简单高效的Json解析器。 读者可在…...
机器学习——KNN数据均一化
在KNN(K-近邻)算法中,数据均一化(归一化)是预处理的关键步骤,用于消除不同特征量纲差异对距离计算的影响。以下是两种常用的归一化操作及其核心要点: 质押 一 、主要思想 1. 最值归一化&#…...
异步编程与流水线架构:从理论到高并发
目录 一、异步编程核心机制解析 1.1 同步与异步的本质区别 1.1.1 控制流模型 1.1.2 资源利用对比 1.2 阻塞与非阻塞的技术实现 1.2.1 阻塞I/O模型 1.2.2 非阻塞I/O模型 1.3 异步编程关键技术 1.3.1 事件循环机制 1.3.2 Future/Promise模式 1.3.3 协程(Cor…...
哈尔滨工业大学DeepSeek公开课人工智能:大模型原理 技术与应用-从GPT到DeepSeek|附视频下载方法
导 读INTRODUCTION 今天继续哈尔滨工业大学车万翔教授带来了一场主题为“DeepSeek 技术前沿与应用”的报告。 本报告深入探讨了大语言模型在自然语言处理(NLP)领域的核心地位及其发展历程,从基础概念出发,延伸至语言模型在机器翻…...
制作Oracle11g Docker 镜像
基于Linux系统,宿主主机要设置如下环境变量,oracle为64位版本 dockerfile中需要的数据库安装包可从csdn下载内找到 #!/bin/bash # 在宿主机上运行以设置Oracle所需的内核参数 # 这些命令需要root权限cat > /etc/sysctl.d/99-oracle.conf << EO…...
Excel处理控件Spire.XLS系列教程:C# 在 Excel 中添加或删除单元格边框
单元格边框是指在单元格或单元格区域周围添加的线条。它们可用于不同的目的,如分隔工作表中的部分、吸引读者注意重要的单元格或使工作表看起来更美观。本文将介绍如何使用 Spire.XLS for .NET 在 C# 中添加或删除 Excel 单元格边框。 安装 Spire.XLS for .NET E-…...
MAC-在使用@Async注解的方法时,分布式锁管理和释放
在使用 @Async 注解的异步方法中管理分布式锁时,需要特别注意 锁的获取、释放与异步执行的生命周期匹配。以下是结合 Spring Boot 和 Redis 分布式锁的实践方案: 1. 为什么需要分布式锁? 异步方法可能被多个线程/服务实例并发执行,若访问共享资源(如数据库、缓存),需…...
Flink启动任务
Flink 以本地运行作为解读,版本1.16.0 文章目录 Flink前言StreamExecutionEnvironmentLocalExecutorMiniCluster启动MiniCluster TaskManagerTaskExecutor提交Task(submitTask) StreamGraph二、使用步骤1.引入库2.读入数据 总结 前言 提示:这里可以添加…...
「低延迟+快速集成:Amazon IVS如何重塑实时互动视频体验?」
引言:实时视频的爆发与开发痛点 随着直播电商、在线教育、云游戏的兴起,实时视频互动成为用户体验的核心。但自建视频服务面临高成本、高延迟、运维复杂等挑战。Amazon IVS(Interactive Video Service)作为亚马逊云科技推出的全托…...
Web开发-JS应用NodeJS原型链污染文件系统Express模块数据库通讯
知识点: 1、安全开发-NodeJS-开发环境&功能实现 2、安全开发-NodeJS-安全漏洞&案例分析 3、安全开发-NodeJS-特有漏洞 node.js就是专门运行javascript的一个应用程序,区别于以往用浏览器解析原生js代码,node.js本身就可以解析执行js代…...
描述@keyframes规则在 CSS 动画中的原理及作用,如何创建一个简单的动画
大白话描述keyframes规则在 CSS 动画中的原理及作用,如何创建一个简单的动画? 嘿,朋友!咱来聊聊 CSS 里超酷的 keyframes 规则。这玩意儿就像是动画的剧本,能让网页元素动起来,就像给它们施了魔法一样&…...
国产达梦(DM)数据库的安装(Linux系统)
目录 一、安装前的准备工作 1.1 导包 1.2 创建用户和组 1.3 修改文件打开最大数 1.4 目录规划 1.5 修改目录权限 二、安装DM8 2.1 挂载镜像 2.2 命令行安装 2.3 配置环境变量 2.4 启动图形化界面 三、配置实例 四、注册服务 五、启动 停止 查看状态 六、数据库客…...
AI日报 - 2025年3月24日
🌟 今日概览(60秒速览) ▎🤖 AGI突破 | Lyra生物序列建模架构效率惊人 在100生物任务中达最优,推理速度提升高达12万倍 ▎💼 商业动向 | OpenAI用户破4亿,Meta与Reliance探讨AI合作 生态扩展与全…...
git的底层原理
git的底层原理 三段话总结git, 1. 工作原理:git管理是一个DAG有向无环图,HEAD指针指向branch或直接指向commit,branch指向commit,commit指向tree,tree指向别的tree或直接指向blob。 2. git所管理的一个目录…...
【Spring】Spring框架介绍
在 Java 企业级应用开发领域,Spring 框架凭借强大功能、高度灵活性与卓越扩展性,成为众多开发者构建大型应用系统的首选。接下来为大家深入剖析 Spring 框架的核心特性、架构设计及实际项目应用。 一、Spring 框架简介 Spring 框架由 Rod Johnson …...
MATLAB+Arduino利用板上的按键控制板上Led灯
几年不使用,之前的知识都忘掉了。需要逐步捡起来。 1 熟悉按键的使用 2熟悉灯的控制 1 电路 我们将通过 MATLAB 的 Arduino 支持包与 Arduino 板通信,读取按键状态并控制 LED 灯的亮灭。 按键:连接到 Arduino 的数字引脚(例如…...
AI比人脑更强,因为被植入思维模型【21】冯诺依曼思维模型
定义 冯诺依曼思维模型是一种基于数理逻辑和系统分析的思维方式,它将复杂的问题或系统分解为若干个基本的组成部分,通过建立数学模型和逻辑规则来描述和分析这些部分之间的关系,进而实现对整个系统的理解和优化。该模型强调从整体到局部、再…...
【QA】Qt中有哪些命令模式的运用?
在 C/Qt 中,命令模式(Command Pattern)的实现通常用于封装操作请求、支持撤销/重做(Undo/Redo)或解耦调用者与接收者。以下是几种常见的实现方式及示例: 1. Qt 的 QUndoCommand 和 QUndoStack(内…...
【连续自然数的和,双指针找区间】
对一个给定的正整数 MM,求出所有的连续的正整数段(每一段至少有两个数),这些连续的自然数段中的全部数之和为 MM。 例子:19981999200020012002100001998199920002001200210000,所以从 19981998 到 2002200…...
Cocos Creator Shader入门实战(五):材质的了解、使用和动态构建
引擎:3.8.5 您好,我是鹤九日! 回顾 前面的几篇文章,讲述的主要是Cocos引擎对Shader使用的一些固定规则,这里汇总下: 一、Shader实现基础是OpenGL ES可编程渲染管线,开发者只需关注顶点着色器和…...
vue设置自定义logo跟标题
准备 Logo 图片 将自定义的 Logo 图片(如 logo.png)放置在项目的 public文件夹下。 使用环境变量设置 Logo 和标题(可选) 创建或修改 .env 文件 在项目根目录下创建或修改 .env 文件,添加以下内容: VITE_A…...
Linux 账号和权限管理命令选项解释
用户账号文件 配置文件 /etc/passwd:用于保存用户 输出如下: root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin 每一行代表一个用户&…...
