尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

React 中 useMemo 和 useCallback 什么时候该用什么时候不该用?

React 中 useMemo 和 useCallback 什么时候该用什么时候不该用?
📅 发布时间:2026/7/30 10:21:02

React 中 useMemo 和 useCallback 什么时候该用什么时候不该用?

一句话总结:不是所有函数和对象都要包一层。只有「传给子组件的引用」或「依赖数组的依赖项」需要稳定引用时才用,否则纯属添乱!


正文目录

  1. useMemo / useCallback 到底解决什么问题?
  2. 5 大高频误用场景 & 修复代码
  3. 万能兜底:三个问题判断该不该用
  4. 预防 checklist(不再踩坑)
  5. 一句话总结

一、useMemo / useCallback 到底解决什么问题?

useMemo缓存计算结果,useCallback缓存函数引用。

// useMemo:缓存计算结果 const expensiveValue = useMemo(() => compute(a, b), [a, b]); // useCallback:缓存函数引用 const handleClick = useCallback(() => doSomething(id), [id]);

本质:它们解决的不是性能问题,而是引用稳定性问题。

React 组件每次渲染,函数体内的变量和函数都会重新创建。如果你把这些新创建的函数/对象传给子组件或放进依赖数组,子组件就会不必要地重渲染,effect 也会不必要地重复执行。

一句话:引用不稳定 → 子组件白渲染 / effect 白执行 → 才需要 useMemo/useCallback。


二、5 大高频误用场景 & 修复代码

① 给没有性能问题的计算包了 useMemo
// ❌ 简单计算包 useMemo,缓存本身比计算还贵 function UserList({ users }) { const count = useMemo(() => users.length, [users]); // ❌ 求个长度还缓存? return <div>共 {count} 人</div>; }

修复:直接算

// ✅ 简单计算不需要缓存 function UserList({ users }) { const count = users.length; // ✅ 直接取 return <div>共 {count} 人</div>; }
② 给不传给子组件的函数包了 useCallback
// ❌ 函数只在当前组件用,包了 useCallback 没意义 function Form() { const [value, setValue] = useState(''); const handleChange = useCallback((e) => { // ❌ 没传给子组件,纯浪费 setValue(e.target.value); }, []); return <input value={value} onChange={handleChange} />; }

修复:原生元素不需要稳定引用

// ✅ 原生 input 不需要 useCallback function Form() { const [value, setValue] = useState(''); const handleChange = (e) => { // ✅ 直接定义 setValue(e.target.value); }; return <input value={value} onChange={handleChange} />; }
③ 传给 memo 子组件的函数没包 useCallback,memo 白写了
// ❌ 子组件用了 memo,但父组件每次传新函数引用 → memo 失效 const Child = memo(({ onClick }) => { console.log('Child rendered'); // ❌ 每次父组件渲染都触发 return <button onClick={onClick}>Click</button>; }); function Parent() { const [count, setCount] = useState(0); const handleClick = () => { // ❌ 每次渲染新函数 console.log('clicked'); }; return ( <> <button onClick={() => setCount(c => c + 1)}>+1</button> <Child onClick={handleClick} /> </> ); }

修复:用 useCallback 稳定引用

// ✅ useCallback 稳定引用,memo 生效 const Child = memo(({ onClick }) => { console.log('Child rendered'); // ✅ 只有 props 变才渲染 return <button onClick={onClick}>Click</button>; }); function Parent() { const [count, setCount] = useState(0); const handleClick = useCallback(() => { // ✅ 引用稳定 console.log('clicked'); }, []); return ( <> <button onClick={() => setCount(c => c + 1)}>+1</button> <Child onClick={handleClick} /> </> ); }
④ useCallback 的依赖项写错,闭包陷阱
// ❌ 依赖数组写了空,但函数里用了 state → 闭包旧值 function Timer() { const [count, setCount] = useState(0); const handleTick = useCallback(() => { console.log(count); // ❌ 永远打印 0,闭包陷阱 setCount(count + 1); }, []); // ❌ 空依赖 }

修复方案一:把依赖加上

// ✅ 加上依赖 const handleTick = useCallback(() => { console.log(count); setCount(count + 1); }, [count]); // ✅ count 变化时更新

修复方案二:用函数式更新

// ✅ 函数式更新,不需要 count 依赖 const handleTick = useCallback(() => { setCount(prev => prev + 1); // ✅ 不依赖外部 count }, []);
⑤ useMemo 缓存对象,但依赖项是引用不稳定的
// ❌ 依赖项是每次新建的对象 → useMemo 每次都重新计算 function Search({ query }) { const params = { keyword: query, page: 1 }; const results = useMemo(() => { return fetchData(params); // ❌ params 每次新对象 → memo 失效 }, [params]); // ❌ params 引用不稳定 }

修复:依赖原始值而非对象

// ✅ 依赖原始值,而非对象 function Search({ query }) { const results = useMemo(() => { return fetchData({ keyword: query, page: 1 }); // ✅ 对象在内部创建 }, [query]); // ✅ 只依赖原始值 }

三、万能兜底:三个问题判断该不该用

问自己三个问题:

1. 这个函数/对象会被传给子组件吗? ├── 否 → 不需要用 └── 是 → 看第 2 题 2. 子组件用了 memo 吗? ├── 否 → 不需要用 └── 是 → 看第 3 题 3. 这个函数/对象会作为 useEffect 的依赖吗? ├── 否 → 可能不需要用(除非 memo 子组件) └── 是 → 必须用 useCallback/useMemo 稳定引用

快速参考表:

场景需要 useMemo/useCallback?
原生元素的事件处理❌ 不需要
简单计算(加减乘除、取属性)❌ 不需要
传给 memo 子组件的 props✅ 需要
useEffect 的函数/对象依赖✅ 需要
大量数据处理(排序、过滤大数据集)✅ 需要
只在当前组件用的函数❌ 不需要
传给第三方组件的高频回调✅ 可能需要

万能模板:

import { useState, useCallback, useMemo, memo } from 'react'; // ✅ 子组件 memo const ExpensiveChild = memo(({ data, onUpdate }) => { return <div>{data.map(item => <div key={item.id}>{item.name}</div>)}</div>; }); function Parent() { const [keyword, setKeyword] = useState(''); const [rawData, setRawData] = useState([]); // ✅ 传给 memo 子组件 → 用 useCallback const handleUpdate = useCallback((id) => { setRawData(prev => prev.map(item => item.id === id ? { ...item, name: 'updated' } : item )); }, []); // ✅ 大量数据过滤 → 用 useMemo const filteredData = useMemo(() => { return rawData.filter(item => item.name.includes(keyword)); }, [rawData, keyword]); // ✅ 依赖原始值 return ( <> <input value={keyword} onChange={e => setKeyword(e.target.value)} /> <ExpensiveChild data={filteredData} onUpdate={handleUpdate} /> </> ); }

四、预防 checklist

  • 不要无脑包:原生元素的事件、简单计算不需要 useMemo/useCallback
  • memo 子组件的 props 必须稳定:传函数用 useCallback,传对象用 useMemo
  • useEffect 的依赖是函数/对象时:必须用 useCallback/useMemo 稳定引用
  • 依赖数组写原始值:别把引用不稳定的对象放进依赖数组
  • 闭包陷阱:useCallback 里用了 state 就要加依赖,或用函数式更新
  • 先写对再优化:先让代码跑起来,出现不必要的重渲染再加 memo + useCallback
  • useCallback 的依赖和 useMemo 一样:变了就重建,没变就复用

五、一句话总结

「useMemo / useCallback 解决的是引用稳定性,不是性能」。只有传给 memo 子组件的 props 或作为 effect 依赖时才需要,其他场景直接定义。先写对,再优化,别上来就全包一层!


最后问候亲爱的朋友们,并邀请你们阅读我的全新著作

📚 《React 进阶实战》

相关新闻

  • 2026 石家庄长安区防水补漏权威攻略:卫生间免砸砖堵漏、屋面防渗、外墙修漏、阳台防水正规施工 + 明细报价 - 超人防水
  • 2026年一站式加工定制机箱钣金:三大核心趋势 - 全域品牌推荐
  • 3步快速恢复QQ空间历史数据:GetQzonehistory完整指南

最新新闻

  • AI聊天机器人为何健忘?解析大模型记忆机制与解决方案
  • 2026年Product Hunt热榜:AI工具与开发者工具新趋势
  • 如何快速掌握微信自动抢红包:新手指南与完整教程
  • 高效优化《冰与火之舞》:9个实用模组功能打造专业游戏体验
  • 南非新能源展
  • 深圳机器视觉培训:零基础入门到项目实战精讲

日新闻

  • 终极TeamSpeak3音乐机器人搭建指南:5分钟实现语音聊天室音频播放
  • 广州海珠区内搬家攻略,平价靠谱搬家服务商推荐,专业打包搬运省心避坑全流程指南 - 厚道搬家
  • 大语言模型入门指南:从零到精通掌握AI核心技术的5大步骤

周新闻

  • 大连理工大学与东京大学联手打造的“主动型AI助手“
  • 170.2026年国家级科研瓶颈:超精密单点金刚石切削(SPDT)光学表面生成
  • SongBloom:革命性歌曲生成框架深度解析——如何通过交织自回归与扩散模型创作完整音乐

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号