当前位置: 首页 > news >正文

比较useCallback、useMemo 和 React.memo

一、核心概念解析

API类型作用返回值
useCallbackReact Hook缓存函数引用记忆化的函数
useMemoReact Hook缓存计算结果记忆化的值
React.memo高阶组件(HOC)缓存组件渲染结果优化后的组件

二、详细说明与代码示例

1、useCallback: 缓存函数引用

const memoizedFn = useCallback(() => {// 函数逻辑
}, [dependencies]);
  • 解决的问题: 防止函数引用频繁变化导致子组件无效重渲染
  • 典型场景:
    • 函数作为 props 传递给优化过的子组件(React.memo
    • 函数作为其他 Hook 的依赖项(如useEffect
// 父组件
function Parent() {const [count, setCount] = useState(0);// ✅ 缓存函数引用const increment = useCallback(() => setCount(c => c + 1), []);return <Child onIncrement={increment} />;
}// 子组件(使用 React.memo 优化)
const Child = React.memo(({ onIncrement }) => {console.log('子组件渲染');return <button onClick={onIncrement}>+</button>;
});

2、useMemo:缓存计算结果

const memoizedValue = useMemo(() => {// 复杂计算return computeExpensiveValue(a, b);
}, [a, b]);
  • 解决的问题: 避免重复执行昂贵的计算
  • 典型场景:
    • 复杂计算(如数据转换、筛选)
    • 保持对象/数组引用稳定(避免作为props传递时触发重渲染)
function Component({ items }) {// ✅ 缓存计算结果const filteredItems = useMemo(() => {return items.filter(item => item.value > 100);}, [items]);return <List items={filteredItems} />;
}

React.memo: 缓存组件渲染

const MemoizedComponent = React.memo(Component, arePropsEqual?);
  • 解决的问题: 避免父组件更新导致子组件不必要的重渲染
  • 工作方式:
    • 对props进行浅比较(可自定义比较函数)
    • props未变化时复用上次渲染结果
// 基础用法
const UserCard = React.memo(({ user }) => {return <div>{user.name}</div>;
});// 自定义比较函数
const UserCard = React.memo(({ user }) => {...},(prevProps, nextProps) => prevProps.user.id === nextProps.user.id
);

三、三者区别对比

特性useCallbackuseMemoReact.memo
优化目标函数引用计算结果组件渲染
返回内容函数任何值组件
触发条件依赖变化时重建函数依赖变化时重新计算props变化时重渲染
内存开销缓存函数缓存值缓存虚拟DOM
典型使用位置组件内部组件内部组件导出时
性能影响减少子组件重渲染减少计算开销减少DOM操作

四、协同工作示例

import React, {useState, useCallback, useMemo} from 'react';// 使用React.memo优化的子组件
const Chart = React.memo((data, onClick) => {console.log('渲染');return <svg onClick={onClick}>...</svg>;
})function Dashboard() {const [data, setData] = useState([]);const [filter, setFilter] = useState('month');// ✅ 缓存函数引用const handleClick = useCallback(() => {console.log('图表点击');}, []);//✅ 缓存计算结果const filteredData = useMemo(() => {return data.filter(d => d.period === filter);}, [data, filter]);return (<div><Chartdata={filteredData}  // 稳定引用onClick={handleClick}  // 稳定引用/></div>);
}

优化效果:
1、filter变化 → filteredData重新计算 → Chart重渲染
2、父组件状态更新 → handleClick引用不变 → Chart 不重渲染
3、点击图表 → 触发缓存的handleClick

五、使用误区与最佳实践

常见错误:

// ❌ 错误1:缺少依赖项
const badCallback = useCallback(() => {console.log(count);  // 永远输出初始值
}, []);  // 缺少count 依赖// ❌ 错误2:滥用useMemo
const simpleValue = useMemo(() => 42, []);  // 直接使用 const 更高效// ❌ 错误3:期待 React.memo 深比较
React.memo(Comonent);  // 默认只做浅比较

黄金法则:
1、按需优化: 先用常规写法,出现性能问题再优化
2、组合使用:
- React.memo + useCallback 优化组件树
- useMemo + useCallback 稳定复杂依赖
3、依赖诚实: 始终声明所有依赖项
4、避免深比较: 复杂对象考虑使用ID比对而非完整对象

六、性能影响分析

操作内存开销CPU开销适用场景
使用useCallback缓存函数依赖比较函数传递/依赖项稳定化
使用useMemo缓存值依赖比较 + 计算昂贵计算/引用稳定化
使用React.memo缓存VDOMProps比较重渲染成本高的叶子组件
三者组合较高大型组件/频繁更新场景
不使用优化简单组件/无性能瓶颈

经验总结: 在10%需要优化的关键路径上使用这些API,避免在简单组件中过度优化。

http://www.lryc.cn/news/615553.html

相关文章:

  • leetcode 11. 盛最多水的容器 -java
  • 欢迎走进《励曼旋耕》
  • HarvardX TinyML小笔记1(番外2:神经网络)
  • 物联网之常见网络配置
  • UE破碎Chaos分配模型内部面材质
  • 编程速递:2025 年巴西 Embarcadero 会议,期待您的到来
  • 【unitrix数间混合计算】2.10 小数部分特征(bin_frac.rs)
  • 【QT】QMainWindow:打造专业级桌面应用的基石
  • pdf预览Vue-PDF-Embed
  • Linux下管道的实现
  • js获取当前时间
  • 基于dynamic的Druid 与 HikariCP 连接池集成配置区别
  • Web自动化技术选择
  • [Oracle] TRUNC()函数
  • 11. 为什么要用static关键字
  • Qt Graphics View框架概述
  • SpringBoot日志关系
  • 分治-快排-面试题 17.14.最小k个数-力扣(LeetCode)
  • 【Datawhale AI夏令营】让AI读懂财报PDF(多模态RAG)(Task 2)
  • 【无标题】六边形结构在二维拓扑量子色动力学模型中确实具有独特优势,并构建完整的二维拓扑量子色动力学模型。
  • QToolBar 的 addPermanentWidget() 详解与实战场景
  • Python如何将图片转换为PDF格式
  • [SC]SystemC 常见的编译/语法错误与解法(三)
  • PowerShell 入门系列(五):运行命令与命令剖析详解
  • Effective C++ 条款32:确定你的public继承塑模出 is-a 关系
  • pytorch+tensorboard+可视化CNN
  • ubuntu dpkg命令使用指南
  • 【线性代数】其他
  • 机器翻译实战:使用Gensim训练中英文词向量模型及可视化
  • leetcode-C语言-3479.水果成篮 III