news 2026/6/15 6:04:20

React 性能优化:memo、useMemo 与 useCallback 用法

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
React 性能优化:memo、useMemo 与 useCallback 用法

你在 React 项目开发中,是不是遇到过组件无意义重复渲染、复杂计算耗时过长的问题?比如父组件仅仅修改自身状态,子组件却跟着重新渲染;每次渲染都执行复杂的数组过滤、排序,导致页面卡顿。React 提供的 memo、useMemo、useCallback 三个优化工具,能精准解决这些性能痛点,让组件渲染更高效。本文结合实战代码,带你吃透这三个工具的核心用法,轻松实现 React 项目性能优化。

一、核心认知:三个工具的优化定位

在使用之前,先明确三者的优化场景,避免用错地方反而增加代码复杂度:

  1. memo:用于优化函数组件的重复渲染,针对「组件本身无变化却因父组件渲染而被迫渲染」的场景,相当于类组件的 PureComponent。
  2. useMemo:用于缓存复杂计算的结果,避免每次组件渲染都重复执行耗时计算,返回的是「计算结果」。
  3. useCallback:用于缓存函数的引用,避免每次组件渲染都创建新的函数实例,返回的是「函数本身」。

三者的核心共性:通过缓存减少不必要的计算和渲染,提升组件执行效率。

二、实战一:memo 优化组件重复渲染

memo 是一个高阶组件,接收一个函数组件作为参数,返回一个优化后的组件。它会浅比较组件的 props,只有当 props 发生变化时,组件才会重新渲染。

1. 未优化的问题示例

父组件修改自身状态,子组件无 props 变化却跟着重复渲染:

import React, { useState } from 'react'; // 子组件:无 props 依赖,却会随父组件渲染而重复渲染 function ChildComponent() { console.log('子组件:无意义重复渲染了'); return <div style={{ marginTop: '20px' }}>我是子组件,无 props 传入</div>; } // 父组件 function ParentComponent() { const [count, setCount] = useState(0); return ( <div style={{ padding: '20px', border: '1px solid #eee', borderRadius: '8px' }}> <h3>父组件计数器:{count}</h3> <button onClick={() => setCount(count + 1)}>点击+1</button> <ChildComponent /> </div> ); } export default ParentComponent;

2. 使用 memo 优化后的示例

import React, { useState, memo } from 'react'; // 优化:用 memo 包裹子组件,避免无意义重复渲染 const ChildComponent = memo(() => { console.log('子组件:只有 props 变化才会渲染'); return <div style={{ marginTop: '20px' }}>我是子组件,无 props 传入</div>; }); // 父组件(代码不变) function ParentComponent() { const [count, setCount] = useState(0); return ( <div style={{ padding: '20px', border: '1px solid #eee', borderRadius: '8px' }}> <h3>父组件计数器:{count}</h3> <button onClick={() => setCount(count + 1)}>点击+1</button> <ChildComponent /> </div> ); } export default ParentComponent;

3. memo 核心说明

  • memo 仅做「浅比较」:如果 props 是对象/数组类型,仅比较引用地址,不深入比较内部属性;
  • 若需深比较,可传递第二个参数(自定义比较函数),但不推荐(深比较本身会消耗性能);
  • memo 仅优化子组件因父组件渲染导致的无意义渲染,若组件自身状态变化,仍会正常渲染。

三、实战二:useCallback 缓存函数引用

当父组件向子组件传递函数 props 时,每次父组件渲染都会创建新的函数实例,导致子组件的 props 引用变化,即使使用 memo 也无法阻止子组件重复渲染。此时需要 useCallback 缓存函数引用。

优化示例

import React, { useState, memo, useCallback } from 'react'; // 子组件:接收函数 props const ChildComponent = memo(({ onHandleClick }) => { console.log('子组件:函数 props 引用未变化,不渲染'); return <button onClick={onHandleClick} style={{ marginTop: '10px' }}>子组件按钮</button>; }); // 父组件 function ParentComponent() { const [count, setCount] = useState(0); // 优化:用 useCallback 缓存函数,仅当依赖变化时才创建新函数 const handleChildClick = useCallback(() => { console.log('子组件按钮被点击'); }, []); // 空依赖:函数引用永久缓存,除非组件卸载 return ( <div style={{ padding: '20px', border: '1px solid #eee', borderRadius: '8px' }}> <h3>父组件计数器:{count}</h3> <button onClick={() => setCount(count + 1)}>点击+1</button> <ChildComponent onHandleClick={handleChildClick} /> </div> ); } export default ParentComponent;

useCallback 核心说明

  • useCallback 接收两个参数:需要缓存的函数、依赖数组;
  • 只有当依赖数组中的变量发生变化时,才会创建新的函数实例,否则返回缓存的函数引用;
  • 通常与 memo 配合使用,单独使用 useCallback 无优化意义。

四、实战三:useMemo 缓存复杂计算结果

当组件中存在复杂计算(如大数据数组排序、过滤、数学运算)时,每次组件渲染都会重复执行这些计算,消耗大量性能。useMemo 可以缓存计算结果,仅当依赖变化时才重新计算。

优化示例

import React, { useState, useMemo } from 'react'; // 模拟复杂计算:大数据数组过滤与排序 function complexCalculation(list) { console.log('执行复杂计算...'); return list.filter(item => item > 50).sort((a, b) => b - a); } function CalculationDemo() { const [count, setCount] = useState(0); // 模拟大数据数组 const numberList = [12, 67, 89, 34, 90, 56, 78, 23]; // 优化:用 useMemo 缓存计算结果,仅当 numberList 变化时才重新计算 const resultList = useMemo(() => { return complexCalculation(numberList); }, [numberList]); // 依赖:仅 numberList 变化时重新计算 return ( <div style={{ padding: '20px', border: '1px solid #eee', borderRadius: '8px' }}> <h3>父组件计数器:{count}</h3> <button onClick={() => setCount(count + 1)}>点击+1</button> <div style={{ marginTop: '20px' }}> <h4>复杂计算结果(大于50的数降序排列):</h4> <p>{resultList.join(', ')}</p> </div> </div> ); } export default CalculationDemo;

useMemo 核心说明

  • useMemo 接收两个参数:计算函数、依赖数组;
  • 计算函数的返回值即为缓存结果,组件渲染时若依赖未变化,直接返回缓存结果,不执行计算函数;
  • 避免用 useMemo 缓存简单计算(如 count + 1),缓存本身也有开销,反而得不偿失;
  • useMemo 还能用于避免传递给子组件的对象/数组 props 引用频繁变化(配合 memo 使用)。

五、避坑指南与最佳实践

  1. 避免过度优化:只有当组件出现明显性能问题(如卡顿、重复渲染频繁)时,才使用这三个工具,不要一上来就无脑优化,增加代码复杂度。
  2. 依赖数组不要遗漏:useCallback 和 useMemo 的依赖数组必须包含所有在内部使用的组件变量,否则会获取到旧值,导致逻辑异常。
  3. memo 不解决深比较问题:若子组件 props 是复杂对象,不要依赖 memo 阻止渲染,优先简化 props,或使用不可变数据(如 Immer)。
  4. useMemo 与 useCallback 区分使用:需要缓存「计算结果」用 useMemo,需要缓存「函数引用」用 useCallback,不要混淆。
  5. 避免在 useMemo/useCallback 中执行副作用:副作用逻辑应放在 useEffect 中,这两个工具仅用于缓存,执行副作用会导致不可预期的问题。

六、总结

React 中 memo、useMemo、useCallback 的核心价值在于「减少不必要的渲染和计算,提升组件性能」,核心要点可概括为:

  1. memo:优化函数组件重复渲染,浅比较 props,仅当 props 变化时才渲染。
  2. useCallback:缓存函数引用,配合 memo 避免子组件因函数 props 引用变化而重复渲染。
  3. useMemo:缓存复杂计算结果,仅当依赖变化时才重新计算,提升渲染效率。
  4. 避坑关键:不过度优化、不遗漏依赖、区分使用场景、不执行副作用。
  5. 核心原则:性能优化以「解决实际问题」为前提,优先保证代码可读性,再进行针对性优化。

掌握这三个工具的用法,你可以轻松解决 React 项目中的常见性能问题,让组件渲染更高效,为用户带来更流畅的使用体验。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 13:07:37

毕业设计项目 基于LSTM的预测算法

文章目录0 简介1 基于 Keras 用 LSTM 网络做时间序列预测2 长短记忆网络3 LSTM 网络结构和原理3.1 LSTM核心思想3.2 遗忘门3.3 输入门3.4 输出门4 基于LSTM的天气预测4.1 数据集4.2 预测示例5 基于LSTM的股票价格预测5.1 数据集5.2 实现代码6 lstm 预测航空旅客数目数据集预测代…

作者头像 李华
网站建设 2026/6/10 13:13:38

孤能子视角:“宇宙学“

(以下是宇宙学和研究宇宙学的主要关系线及其边界。姑且当科幻小说看)信兄回答1:宇宙学。我将以EIS的“元三力-五要点-六线”自主循环分析心法&#xff0c;对宇宙学进行一次完整的关系动力学扫描。启动阶段&#xff1a;零预设&#xff0c;元三力逼问1. 存续驱动逼问 宇宙学作为认…

作者头像 李华
网站建设 2026/6/10 13:11:43

springboot146基于Java Web的老年人饮食健康档案管理系统的设计与实现

目录具体实现截图摘要系统所用技术介绍写作提纲源码文档获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&#xff01;具体实现截图 摘要 随着老龄化社会的加速发展&#xff0c;老年人的健康管理问题日益受到关注&#xff0c;饮食健康作为老年人健康管理的重…

作者头像 李华
网站建设 2026/6/10 13:14:59

springboot147基于JavaEE的服饰服装商城网站的设计与实现

目录 具体实现截图摘要 系统所用技术介绍写作提纲源码文档获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&#xff01; 具体实现截图 摘要 随着电子商务的快速发展&#xff0c;服饰服装商城网站成为消费者在线购物的主要渠道之一。基于JavaEE技术栈的Spri…

作者头像 李华
网站建设 2026/6/10 13:15:24

【毕业设计】基于python-CNN深度学习识别是否发生火灾

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/6/10 13:11:42

http和https区别、令牌、三次握手流程

一、HTTP 和 HTTPS 的区别&#xff08;必背&#xff09;1️⃣ 本质区别&#xff08;一句话&#xff09;HTTP 是明文传输&#xff0c;HTTPS 是在 HTTP 基础上加了一层 SSL/TLS 加密。2️⃣ 核心对比表对比项HTTPHTTPS是否加密❌ 明文✅ 加密安全性低高端口80443证书不需要需要 C…

作者头像 李华