React 中useMemo和useCallback Hook 的作用,在什么场景下使用它们?

news2025/3/26 15:36:36

大白话React 中useMemo和useCallback Hook 的作用,在什么场景下使用它们?

在 React 里,useMemouseCallback 这两个 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

useCallbackuseMemo 有点像,但它主要是用来缓存函数的。在 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]); // 依赖项数组包含 count

    return (
        <div>
            <p>计数: {count}</p>
            {/* 传递缓存的函数给子组件 */}
            <ChildComponent onClick={handleClick} />
        </div>
    );
};

export default ParentComponent;    
代码解释:
  • useCallback 也接收两个参数,第一个参数是要缓存的函数,第二个参数是依赖项数组。
  • 只要依赖项数组里的值不变,useCallback 返回的函数引用就不会变。
使用场景:
  • 当把函数作为 props 传递给子组件时,用 useCallback 可以避免子组件因为函数引用的变化而不必要的重新渲染。
  • 当函数是作为依赖项传递给其他 Hook(比如 useEffect)时,用 useCallback 可以保证函数引用的稳定性。

总的来说,useMemo 主要用于缓存计算结果,useCallback 主要用于缓存函数,合理使用它们能让 React 应用的性能更上一层楼!

除了性能优化,useMemo和useCallback还有哪些应用场景

除了性能优化外,useMemouseCallback 在 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>
            <input
                type="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;

这些场景展示了 useMemouseCallback 在除性能优化之外的其他用途,它们可以帮助开发者更好地管理组件的状态和行为。

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 函数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2320908.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SQL Server——表数据的插入、修改和删除

目录 一、引言 二、表数据的插入、修改和删除 &#xff08;一&#xff09;方法一&#xff1a;在SSMS控制台上进行操作 1.向表中添加数据 2.对表中的数据进行修改 3.对表中的数据进行删除 &#xff08;二&#xff09;方法二&#xff1a;使用 SQL 代码进行操作 1.向表中添…

deepSeek-SSE流式推送数据

1、背景 DeepSeek作为当前最火的AI大模型&#xff0c; 使用的时候用户在输入框输入问题&#xff0c;大模型进行思考回答你&#xff0c;然后会有一个逐步显示的过程效果&#xff0c;而不是一次性返回整个答案给前端页面进行展示&#xff0c;为了搞清楚其中的原理&#xff0c;我们…

【北京迅为】iTOP-RK3568开发板OpenHarmony系统南向驱动开发UART接口运作机制

瑞芯微RK3568芯片是一款定位中高端的通用型SOC&#xff0c;采用22nm制程工艺&#xff0c;搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码&#xff0c;支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU&#xff0c;可用于轻量级人工…

C#实现自己的Json解析器(LALR(1)+miniDFA)

C#实现自己的Json解析器(LALR(1)miniDFA) Json是一个用处广泛、文法简单的数据格式。本文介绍如何用bitParser&#xff08;拥有自己的解析器&#xff08;C#实现LALR(1)语法解析器和miniDFA词法分析器的生成器&#xff09;迅速实现一个简单高效的Json解析器。 读者可在&#xf…

机器学习——KNN数据均一化

在KNN&#xff08;K-近邻&#xff09;算法中&#xff0c;数据均一化&#xff08;归一化&#xff09;是预处理的关键步骤&#xff0c;用于消除不同特征量纲差异对距离计算的影响。以下是两种常用的归一化操作及其核心要点&#xff1a; 质押 一 、主要思想 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 协程&#xff08;Cor…

哈尔滨工业大学DeepSeek公开课人工智能:大模型原理 技术与应用-从GPT到DeepSeek|附视频下载方法

导 读INTRODUCTION 今天继续哈尔滨工业大学车万翔教授带来了一场主题为“DeepSeek 技术前沿与应用”的报告。 本报告深入探讨了大语言模型在自然语言处理&#xff08;NLP&#xff09;领域的核心地位及其发展历程&#xff0c;从基础概念出发&#xff0c;延伸至语言模型在机器翻…

Excel处理控件Spire.XLS系列教程:C# 在 Excel 中添加或删除单元格边框

单元格边框是指在单元格或单元格区域周围添加的线条。它们可用于不同的目的&#xff0c;如分隔工作表中的部分、吸引读者注意重要的单元格或使工作表看起来更美观。本文将介绍如何使用 Spire.XLS for .NET 在 C# 中添加或删除 Excel 单元格边框。 安装 Spire.XLS for .NET E-…

Web开发-JS应用NodeJS原型链污染文件系统Express模块数据库通讯

知识点&#xff1a; 1、安全开发-NodeJS-开发环境&功能实现 2、安全开发-NodeJS-安全漏洞&案例分析 3、安全开发-NodeJS-特有漏洞 node.js就是专门运行javascript的一个应用程序&#xff0c;区别于以往用浏览器解析原生js代码&#xff0c;node.js本身就可以解析执行js代…

国产达梦(DM)数据库的安装(Linux系统)

目录 一、安装前的准备工作 1.1 导包 1.2 创建用户和组 1.3 修改文件打开最大数 1.4 目录规划 1.5 修改目录权限 二、安装DM8 2.1 挂载镜像 2.2 命令行安装 2.3 配置环境变量 2.4 启动图形化界面 三、配置实例 四、注册服务 五、启动 停止 查看状态 六、数据库客…

git的底层原理

git的底层原理 三段话总结git&#xff0c; 1. 工作原理&#xff1a;git管理是一个DAG有向无环图&#xff0c;HEAD指针指向branch或直接指向commit&#xff0c;branch指向commit&#xff0c;commit指向tree&#xff0c;tree指向别的tree或直接指向blob。 2. git所管理的一个目录…

MATLAB+Arduino利用板上的按键控制板上Led灯

几年不使用&#xff0c;之前的知识都忘掉了。需要逐步捡起来。 1 熟悉按键的使用 2熟悉灯的控制 1 电路 我们将通过 MATLAB 的 Arduino 支持包与 Arduino 板通信&#xff0c;读取按键状态并控制 LED 灯的亮灭。 按键&#xff1a;连接到 Arduino 的数字引脚&#xff08;例如…

Cocos Creator Shader入门实战(五):材质的了解、使用和动态构建

引擎&#xff1a;3.8.5 您好&#xff0c;我是鹤九日&#xff01; 回顾 前面的几篇文章&#xff0c;讲述的主要是Cocos引擎对Shader使用的一些固定规则&#xff0c;这里汇总下&#xff1a; 一、Shader实现基础是OpenGL ES可编程渲染管线&#xff0c;开发者只需关注顶点着色器和…

vue设置自定义logo跟标题

准备 Logo 图片 将自定义的 Logo 图片&#xff08;如 logo.png&#xff09;放置在项目的 public文件夹下。 使用环境变量设置 Logo 和标题&#xff08;可选&#xff09; 创建或修改 .env 文件 在项目根目录下创建或修改 .env 文件&#xff0c;添加以下内容&#xff1a; VITE_A…

尝试在软考65天前开始成为软件设计师-计算机网络

OSI/RM 七层模型 层次名功能主要协议7应用层实现具体应用功能 FTP(文件传输)、HTTP、Telnet、 POP3(邮件)SMTP(邮件) ------- DHCP、TFTP(小文件)、 SNMP、 DNS(域名) 6表示层数据格式,加密,压缩.....5会话层建立,管理&终止对话4传输层端到端连接TCP,UDP3网络层分组传输&a…

VMware主机换到高配电脑,高版本系统的问题

原来主机是i3 ,windows7系统&#xff0c;vmware 14.0,虚机系统是ubuntu 14.04。目标新机是i7 14700KF,windows11系统。原以为安装虚拟机&#xff0c;将磁盘文件&#xff0c;虚拟机配置文件拷贝过去可以直接用。 新目标主机先安装了vmware 15&#xff0c;运行原理虚机&#xff0…

【Linux内核系列】:动静态库详解

&#x1f525; 本文专栏&#xff1a;Linux &#x1f338;作者主页&#xff1a;努力努力再努力wz &#x1f4aa; 今日博客励志语录&#xff1a; 有些鸟儿是注定是关不住的&#xff0c;因为它们的每一片羽翼都沾满了自由的光辉 ★★★ 本文前置知识&#xff1a; 编译与链接的过程…

windows环境下NER Python项目环境配置(内含真的从头安的perl配置)

注意 本文是基于完整项目的环境配置&#xff0c;即本身可运行项目你拿来用 其中有一些其他问题&#xff0c;知道的忽略即可 导入pycharm基本包怎么下就不说了&#xff08;这个都问&#xff1f;给你一拳o(&#xff40;ω*)o&#xff09; 看perl跳转第5条 1.predict报错多个设备…

IDEA批量替换项目下所有文件中的特定内容

文章目录 1. 问题引入2. 批量替换项目下所有文件中的特定内容2.1 右键项目的根目录&#xff0c;点击在文件中替换2.2 输入要替换的内容 3. 解决替换一整行文本后出现空行的问题4. 增加筛选条件提高匹配的精确度 更多 IDEA 的使用技巧可以查看 IDEA 专栏&#xff1a; IDEA 1. 问…

【蓝桥杯】4535勇闯魔堡(多源BFS + 二分)

思路 k有一个范围&#xff08;0到怪物攻击的最大值&#xff09;&#xff0c;求满足要求的k的最小值。很明显的二分套路。 关键是check函数怎么写&#xff0c;我们需要找到一条从第一行到最后一行的路径&#xff0c;每一次可以从上下左右四个方向前进&#xff0c;那么我么可以用…