掌握 React.memo、useCallback、useMemo 的正确使用姿势,让你的 React 应用性能飞起来!


🎯 React.memo 作用

React.memo 是一个高阶组件,用于函数组件,通过浅比较 props 的变化来决定是否重新渲染。如果 props 没有变化,组件就会跳过渲染,复用之前的渲染结果,从而提升性能。

🤔 React.memo 可以避免组件重复渲染,是不是所有组件都应该它包裹?

📋 React.memo 使用原则

✅ 什么情况下使用:

🎨 场景 1:组件渲染成本高

如果组件内部有复杂计算、大量子节点或高频交互(如动画、图表),且父组件频繁触发无关渲染时,使用 React.memo 可减少重复渲染。

 场景 2:Props 变化频率低

当组件的 props 大多数情况下稳定,只有少数情况会变化时(如配置型组件),React.memo 能有效避免因父组件状态变化导致的无效渲染。

🔗 场景 3:传递了非稳定 Props

如果父组件传递的 props 是内联对象或函数(如 onClick={() => {...}}),且未通过 useMemo/useCallback 缓存,子组件用 React.memo 可能无效,需结合缓存使用。

❌ 什么情况下不使用:

🪶 场景 1:组件本身渲染成本极低

如果组件只是简单渲染文本或少量 DOM 节点(如 <Button>),React.memo 的 props 浅比较成本可能高于直接渲染的成本,得不偿失。

🔄 场景 2:Props 频繁变化

如果组件的 props 每次渲染几乎都会变化(如实时更新的数据流),使用 React.memo 反而会增加额外的浅比较开销,优化效果微乎其微。

🍃 场景 3:组件已经是”叶子组件”

如果组件没有子组件,且不受父组件状态影响,通常不需要额外优化。

💡 其他优化方式

如果不想滥用 React.memo,可通过其他方式减少渲染:

1. 🎯 状态隔离:将状态下沉到更小的组件中,避免全局状态触发大范围渲染。

2. 🧩 组件拆分:将高频变动的部分和低频变动的部分拆分为独立组件。

3. 🔑 使用 key 属性:强制重置组件实例,避免内部状态混乱(如列表项)。

4. 📜 虚拟化长列表:对长列表使用 react-window 或 react-virtualized,减少 DOM 节点数量。


🔄 useCallback 作用

useCallback 是 React 中用于性能优化的钩子,其主要作用是 缓存函数实例,避免子组件因父组件重新渲染导致的非必要更新。

🤔 useCallback 可以缓存方法,是不是所有方法都应该用它优化呢?

📋 useCallback 使用原则

✅ 什么情况下使用:

🎯 场景 1:子组件使用了 React.memo

如果子组件通过 React.memo 避免重复渲染,且父组件传递的方法是一个 非稳定的函数引用(如内联函数),则需要用 useCallback 包裹,否则子组件会因父组件渲染导致函数引用变化而重新渲染。

// 父组件
const Parent = () => {const [count, setCount] = useState(0);// ❌ 未使用 useCallback:每次渲染生成新函数,导致子组件重新渲染const handleClickBad = () => console.log("Click");// ✅ 使用 useCallback:函数引用稳定,子组件不重复渲染const handleClickGood = useCallback(() => {console.log("Click");}, []);return <Child onClick={handleClickGood} />;
};// 子组件
const Child = React.memo(({ onClick }) => {return <button onClick={onClick}>Submit</button>;
});

⚖️ 场景 2:子组件依赖浅比较优化

如果子组件是 PureComponent 或通过 shouldComponentUpdate 实现了浅比较逻辑,父组件传递的函数必须保持引用稳定,否则优化会失效。

class Child extends React.PureComponent {render() {return <button onClick={this.props.onClick}>Submit</button>;}
}
❌ 什么情况下不使用:

🚫 场景 1:子组件无渲染优化

如果子组件没有使用 React.memo、PureComponent 或自定义的渲染优化逻辑,即使父组件传递的函数引用变化,也不会带来明显的性能问题。

// 子组件未优化,函数引用变化不影响性能
const Child = ({ onClick }) => <button onClick={onClick}>Submit</button>;

🔄 场景 2:函数依赖频繁变化的值

如果函数内部依赖频繁变化的 state 或 props,且需要 实时获取最新值,此时 useCallback 需明确声明依赖项,可能导致函数频繁重建,反而失去优化意义。

const Parent = () => {const [text, setText] = useState("");// ❌ 依赖 text 变化,useCallback 无法避免重建const handleSubmit = useCallback(() => {console.log(text); // 需要最新的 text}, [text]);return <Child onSubmit={handleSubmit} />;
};

💡 场景 3:替代方案:直接传递内联函数

如果子组件渲染成本极低(如简单按钮),且父组件渲染频率不高,可以直接传递内联函数,避免过度优化。

const Parent = () => {return <Child onClick={() => console.log("Click")} />;
};

📊 性能权衡建议

🎯 场景是否需要 useCallback💡 原因
子组件通过 React.memo/PureComponent 优化✅ 需要避免函数引用变化导致子组件无效渲染
子组件无优化且渲染成本低❌ 不需要优化收益小于比较成本
函数依赖高频变化的值❌ 谨慎使用可能导致频繁重建函数
函数作为副作用依赖(如 useEffect)✅ 需要避免副作用重复触发

📝 总结

 优先使用 useCallback:当子组件有明确的渲染优化策略时(如 React.memo)。

⚠️ 无需强制使用:如果子组件渲染成本低或函数依赖频繁变化的值。

🚫 避免滥用:过度使用 useCallback 可能导致代码复杂度上升,需结合性能分析工具(如 React DevTools)验证优化效果。


💾 useMemo 作用

useMemo 是 React 中的一个性能优化 Hook,核心作用是通过缓存复杂计算结果,避免组件重复渲染时不必要的重复计算

✅ 什么情况下使用:

🔥 场景 1:高开销计算

当组件内有 计算成本高昂 的操作(如大数据处理、复杂数学运算),且计算结果在多次渲染间可复用时。

const ExpensiveComponent = ({ items }) => {// ✅ 缓存复杂计算结果const expensiveValue = useMemo(() => {return items.reduce((sum, item) => {return sum + complexCalculation(item);}, 0);}, [items]);return <div>{expensiveValue}</div>;
};

🔗 场景 2:引用稳定性

当需要保持对象或数组的 引用稳定,避免子组件因浅比较重新渲染时。

const Parent = ({ data }) => {// ✅ 保持对象引用稳定const memoizedData = useMemo(() => ({processedData: data.map((item) => ({ ...item, processed: true })),metadata: { count: data.length, timestamp: Date.now() },}),

[data]

); return <Child data={memoizedData} />; };

🔄 场景 3:依赖其他 Hook 的中间值

当某个值被多个 Hook 依赖,且需要避免重复计算时。

const Component = ({ users, filters }) => {// ✅ 缓存过滤结果,供多个 Hook 使用const filteredUsers = useMemo(() => {return users.filter((user) => filters.every((filter) => filter(user)));}, [users, filters]);const userCount = useMemo(() => filteredUsers.length, [filteredUsers]);const averageAge = useMemo(() =>filteredUsers.reduce((sum, user) => sum + user.age, 0) /filteredUsers.length,[filteredUsers]);return <UserStats count={userCount} averageAge={averageAge} />;
};

❌ 什么情况下不使用:

🪶 场景 1:简单计算

如果计算成本极低(如基本运算、简单对象合并),直接计算即可。

// ❌ 不必要的优化
const simpleValue = useMemo(() => a + b, [a, b]);// ✅ 直接计算即可
const simpleValue = a + b;

 场景 2:频繁变化的依赖项

如果依赖项频繁变化(如实时输入框的值),缓存效果微乎其微,反而增加开销。

const SearchComponent = ({ query }) => {// ❌ query 频繁变化,缓存意义不大const searchResults = useMemo(() => {return performSearch(query);}, [query]);return <SearchResults results={searchResults} />;
};

🍃 场景 3:组件层级低或渲染压力小

对于叶子组件或渲染压力较小的组件,优化收益低于 useMemo 自身成本。

📊 useMemo 最佳实践

 推荐做法:

  1. 🎯 针对性优化:只对真正昂贵的计算使用 useMemo
  2. 📏 合理的依赖项:确保依赖项数组准确且稳定
  3. 🔍 性能测试:使用 React DevTools 验证优化效果
  4. 🧪 基准测试:对比优化前后的性能差异

 避免的做法:

  1. 🚫 过度优化:不要为每个简单计算都使用 useMemo
  2. ⚠️ 错误依赖:避免遗漏或添加不必要的依赖项
  3. 🔄 频繁重建:避免在依赖项频繁变化时使用

🎉 总结

React 性能优化的三大法宝:React.memouseCallbackuseMemo,各有其适用场景:

🎯 React.memo:适用于渲染成本高、props 变化少的组件
🔄 useCallback:适用于传递给优化子组件的函数
💾 useMemo:适用于昂贵计算和引用稳定性需求

记住:性能优化不是银弹,过度优化反而可能降低性能。始终以实际测试为准,在合适的场景使用合适的优化手段!


💡 小贴士:使用 React DevTools Profiler 来识别性能瓶颈,让优化更有针对性!

 React性能优化终极指南:memo、useCallback、useMemo全解析 - 高质量源码分享平台-免费下载各类网站源码与模板及前沿技术分享

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

借助 VR 消防技术开展应急演练,检验完善应急预案​

应急演练是企业应对火灾事故的重要手段&#xff0c;而 VR 消防技术的应用&#xff0c;为应急演练带来了全新的体验和更高的效率。VR 消防技术通过虚拟现实技术模拟逼真的火灾场景&#xff0c;让参与者能够身临其境地感受火灾发生时的紧张氛围。某知名物流企业&#xff0c;仓库众…

【电赛学习笔记】MaxiCAM 项目实践——二维云台追踪指定目标

前言 本文是对视觉模块MaixCam实现二维云台人脸跟踪_哔哩哔哩_bilibili大佬的项目实践整理与拓展&#xff0c;侵权即删。 单路舵机基本控制 #导入必要模块 from maix import pwm, time , pinmap#定义全局变量&#xff0c;设初值 SERVO_FREQ 50 #主频 SERVO_MIN_DUT…

深入解析 ArkUI 触摸事件机制:从点击到滑动的开发全流程

摘要 随着 HarmonyOS NEXT 的不断发展&#xff0c;ArkUI 逐渐成为主流的 UI 构建方式。而用户交互在任何应用中都是基础而又关键的一环&#xff0c;如何利用 ArkUI 提供的触摸事件机制&#xff0c;如 onTouch、onClick、onSwipe 等&#xff0c;来实现自然、顺滑、用户友好的交互…

Tailwind CSS 自定义工具类与主题配置指南

一、自定义工具类配置在 src/tailwind.css 文件中&#xff0c;我们可以通过 layer utilities 指令添加自定义工具类&#xff1a;tailwind base; tailwind components; tailwind utilities;layer utilities {/* 自定义工具 上下浮动效果 */.animate-floatY {animation: floatY 3…

【代码随想录二刷|704.二分查找、27.移除元素、977.有序数组的平方】

704.二分查找 题目链接&#xff1a;704. 二分查找 - 力扣&#xff08;LeetCode&#xff09; class Solution { public:int search(vector<int>& nums, int target) {//不用二分查找&#xff0c;直接求// for(int i0;i<nums.size();i){// if(nums[i]target)…

基于Vue的工业设备大屏可视化模板(含设备地图分布+宣传模块+报表展示+三维模型加载预览)

场景 为实现工业设备可视化大屏需求&#xff0c;可实现基于地图的设备数据管理&#xff0c;点击具体设备可进行详细介绍和三维模型展示。 可播放宣传视频&#xff0c;可展示PM数据报表等数据&#xff0c;可接受报警数据提醒、统计等数据。 基于现有开源平台框架进行二次改造…

堆(Heap)优先级队列(Priority Queue)

一、堆的概念堆&#xff08;Heap&#xff09;是一种特殊的基于树的数据结构&#xff0c;通常分为最大堆和最小堆两种类型。它满足堆属性&#xff1a;对于最大堆&#xff0c;父节点的值总是大于或等于其子节点的值&#xff1b;而对于最小堆&#xff0c;父节点的值总是小于或等于…

踩坑记录:因版本不匹配导致 Boost 1.85 编译失败的完整解决过程

踩坑记录&#xff1a;因版本不匹配导致 Boost 1.85 编译失败的完整解决过程 转载请注明出处&#xff0c;欢迎评论区交流。 背景 最近在 Windows 11 VS2022 环境下尝试用 b2 编译 Boost 1.85.0&#xff0c;结果一路踩坑&#xff0c;最后发现罪魁祸首是 Boost.Build 自带的 msv…

InfluxDB Line Protocol 协议深度剖析(二)

四、Line Protocol 写入操作与实践&#xff08;一&#xff09;HTTP API 写入使用 HTTP API 是通过 Line Protocol 写入数据到 InfluxDB 的常用方式。InfluxDB 1.x&#xff1a;请求方式为 POST&#xff0c;URL 格式为 “http://host:port/write?dbdatabase_name”。其中&#x…

负载均衡:提升业务性能的关键技术

一.负载均衡&#xff08;3.6 &#xff09;1.1.什么是负载均衡&#xff1a;负载均衡&#xff1a;Load Balance&#xff0c;简称LB&#xff0c;是一种服务或基于硬件设备等实现的高可用反向代理技术&#xff0c;负载均 衡将特定的业务(web服务、网络流量等)分担给指定的一个或多个…

【STM32项目】智能家居(版本1)

✌️✌️大家好&#xff0c;这里是5132单片机毕设设计项目分享&#xff0c;今天给大家分享的是基于《基于STM32的智能家居设计》。 目录 1、系统功能 2.1、硬件清单 2.2、功能介绍 2.3、控制模式 2、演示视频和实物 3、系统设计框图 4、软件设计流程图 5、原理图 6、主…

OpenSCA开源社区每日安全漏洞及投毒情报资讯—2025年7月24日

2025年7月24日安全风险情报资讯在野漏洞风险&#xff08;CVE未收录&#xff09;&#xff1a;1公开漏洞精选&#xff1a;2组件投毒情报&#xff1a;2在野漏洞风险&#xff08;CVE未收录&#xff09;1.1 gemini-cli项目潜在命令注入漏洞项目详情项目描述&#xff1a;gemini-cli是…

飞算 JavaAI 深度实战:从老项目重构到全栈开发的降本增效密码

飞算 JavaAI 深度实战&#xff1a;从老项目重构到全栈开发的降本增效密码引言正文一、智能引导模块&#xff1a;老项目重构的 “手术刀” 级解决方案1.1 本地化智能分析&#xff1a;IDEA 插件实操演示1.1.1 &#x1f4cc; IDEA 插件安装步骤1.1.1.1 首先打开idea工具&#xff0…

分布式推客系统开发全解:微服务拆分、佣金结算与风控设计

一、推客系统概述与市场背景推客系统&#xff08;也称为分销系统或社交电商系统&#xff09;已成为现代电商平台和内容平台的重要增长引擎。根据最新统计数据&#xff0c;2023年社交电商市场规模已突破3万亿元&#xff0c;占整体电商市场份额的25%以上。推客系统的核心价值在于…

Linux tcpdump 抓取udp 报文

一、tcpdump 支持命令选项tcpdump -i # 指定监听网络接口tcpdump -w # 将捕获到的信息保存到文件中&#xff0c;且不分析和打印在屏幕tcpdump -r # 从文件中读取数据tcpdump -n # 不把 ip 转化成域名tcpdump -t # 在每行的输出中不显示时间tcpdump -v # 产生详细的输出tc…

Oracle数据块8KB、OS默认认块管理4KB,是否需调整大小为一致?

上班路上&#xff0c;脑中忽然闪现一个问题&#xff1a;Oracle数据库块大小&#xff08;8KB&#xff09;、操作系统文件系统块大小&#xff08;4KB&#xff09;&#xff0c;为了减少IOPS&#xff0c;需不需要调整为一致&#xff1f;在数据块保持一致的情况下&#xff0c;针对频…

卡尔曼滤波器噪声方差设置对性能影响的仿真研究

卡尔曼滤波器噪声方差设置对性能影响的仿真研究 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家,觉得好请收藏。点击跳转到网站。 1. 引言 卡尔曼滤波器是一种广泛应用于信号处理、控制系统、导航系统等领域的递归估计算法。它通过对系…

“多线程修路:当count++变成灾难现场”

1.现象 当我们操作一个线程池的时候&#xff0c;可能需要去计数&#xff0c;也就是统计count&#xff0c;那我们这里有一个疑问&#xff0c;会不会产生线程安全问题&#xff1f; 毫无疑问绝对会有线程安全问题。在线程池环境中&#xff0c;多个线程并发访问和修改一个共享的 co…

GaussDB null的用法

1 null的定义null 空值代表丢失的未知数据。 默认情况下&#xff0c;表列可以保存 null 值。 本章解释 is null 和 is not null 操作符。2 null值的赘述如果表中的列是可选的&#xff0c;那么我们可以插入一个新记录或更新一个现有记录&#xff0c;而无 需向列添加一个值。这意…

智慧农业新图景:物联网如何精准守护作物生长​

在传统农业生产模式下&#xff0c;农民往往凭借经验判断作物生长需求&#xff0c;灌溉、施肥缺乏精准性&#xff0c;导致水资源浪费、土壤板结、作物产量与品质难以提升等问题。加之气候变化无常&#xff0c;极端天气频发&#xff0c;给农业生产带来诸多不确定性&#xff0c;传…