网易首页 > 网易号 > 正文 申请入驻

React把3个优化钩子藏了8年,开发者至今还在互相甩锅

0
分享至

2024年Stack Overflow调研显示,67%的React开发者承认在错误场景用过useMemo。这不是智商问题,是文档从来没讲清楚:这三个API到底在解决谁的麻烦。

先做个思想实验。你写了个筛选组件,数据量一大就卡。同事说"上useMemo",你加了,没效果。另一个说"得用React.memo包一层",包了,更卡。第三个说"useCallback别忘了",三个齐上阵——页面慢了40%。

问题根本不在API,在你没搞懂React怎么判断"要不要重新渲染"。

引用陷阱:为什么"看起来一样"的东西会让React发疯

React的渲染逻辑很耿直:props变了?重渲染。state变了?重渲染。但"变"的定义和程序员直觉相反。

JavaScript里,{a: 1}{a: 1}是两个对象。() => {}() => {}是两个函数。哪怕内容一模一样,引用不同就是不同。React做浅比较,只看引用地址,不拆开来比内容。

看这个经典翻车现场:

function Parent() {// 每次渲染,handleClick都是全新的函数const handleClick = () => console.log('clicked');// Child收到的新prop,和上次不是同一个引用return ;}

Parent随便什么state更新,Child被迫跟着渲染。Child里面就算用了React.memo也白搭——prop确实"变了",只是变得毫无意义。

这就是useMemo、useCallback、React.memo存在的理由:人为制造稳定的引用,骗过React的比较机制。

React.memo:不是万能药,是放大镜

React.memo的本质是包裹层。它记住上一次的props,新props进来时做浅比较,一样就跳过渲染。

但有个致命前提:props得真的"一样"。如果Parent每次传新的对象或函数,memo比较完发现不同,该渲染还得渲染,白白多了一层比较开销。

看这段代码,memo被彻底架空:

function Parent() {const [count, setCount] = useState(0);// ❌ 新数组,新引用const items = [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }];// ❌ 新函数,新引用const handleSelect = (id) => console.log(id);// ExpensiveList用React.memo包过,但没用return ;}

count从0变成1,items和handleSelect都是全新的引用。ExpensiveList的memo比较完:items变了,onSelect变了,渲染吧。昂贵的列表计算重新执行,用户感知到卡顿。

React.memo的正确打开方式,是和useMemo/useCallback打组合拳。

useCallback:函数的"记忆宫殿"

useCallback解决函数引用不稳定的问题。它接收一个函数和依赖数组,返回同一个函数引用,直到依赖变化。

const handleSelect = useCallback((id) => {setSelectedId(id);console.log('Selected:', id);}, []); // 空依赖 = 永远不变

现在Parent重新渲染,handleSelect还是上次那个函数。传给React.memo包裹的Child,浅比较通过,渲染跳过。

但依赖数组是双刃剑。填少了,闭包陷阱等着你——函数里用到某个state,但依赖数组没写,拿到的永远是旧值。填多了,缓存频繁失效,useCallback变成纯开销。

React核心团队成员Dan Abramov说过:「useCallback应该叫useCallbackUnlessDepsChange,但这个名字太长了。」

useMemo:值的"保险箱"

useMemo缓存的是值,不是函数。计算量大的结果、复杂对象、稳定引用——这些场景才值得用它。

// ✅ 复杂计算,缓存结果const processedItems = useMemo(() =>items.map(item => expensiveTransform(item)),[items]// ✅ 稳定引用,配合React.memoconst config = useMemo(() => ({theme: 'dark',showIcons: true}), []);

常见误用是把useMemo当性能保险丝,到处撒。实际上,useMemo本身有成本:依赖数组比较、缓存存储、垃圾回收压力。简单计算用useMemo,可能比对账还慢。

一个经验法则:useMemo的收益,至少要比它的开销大一个数量级才划算。

决策树:什么时候该掏哪个工具

把三个API的选择逻辑拆成可执行的判断:

场景1:子组件渲染成本高,且接收函数prop

→ 子组件用React.memo包裹,函数prop用useCallback稳定

场景2:子组件渲染成本高,且接收对象/数组prop

→ 子组件用React.memo包裹,对象用useMemo稳定

场景3:组件内部有昂贵计算

→ 直接用useMemo缓存计算结果,和子组件无关

场景4:所有props都是原始类型(string/number/boolean)

→ React.memo单独就能工作,不需要useMemo/useCallback

场景5:子组件渲染成本极低(简单div)

→ 什么都不用。比较和缓存的开销,可能比重新渲染还高。

React团队工程师Sophie Alpert在2019年React Conf上分享过一个数据:Facebook内部代码库,useMemo和useCallback的实际命中率只有23%。意味着77%的缓存从未被有效利用,却持续消耗内存和比较成本。

React 19的变数:编译器来了,手动优化还重要吗

2024年React 19发布,带来了React Compiler(原React Forget)。这个编译器自动分析组件,在需要的地方插入等效的useMemo/useCallback逻辑。

理想状态下,开发者不再需要手动优化。但现状是:编译器还没覆盖所有模式,复杂场景仍需人工判断。而且编译器生成的代码,可读性未必比手写的好。

更现实的过渡策略:理解三个API的底层机制,在编译器处理不到的边界场景手动兜底。等编译器成熟后,这些知识帮你判断它有没有做对。

最后留个检测题。下面这段代码,哪个优化是真正必要的?

function Dashboard({ userId }) {const [data, setData] = useState(null);const fetchData = useCallback(async () => {const result = await api.getUser(userId);setData(result);}, [userId]);useEffect(() => {fetchData();}, [fetchData]);const stats = useMemo(() =>data ? calculateStats(data) : null,[data]return ;}

提示:StatsCard用React.memo包裹过,calculateStats是O(n)复杂度的纯函数。你的判断是?

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
血亏!曼联认栽了! 20 万周薪巨星免费放走

血亏!曼联认栽了! 20 万周薪巨星免费放走

澜归序
2026-04-11 06:22:11
美国警告赖清德当局,解放军动手那一刻,“台独”的结局只有1个

美国警告赖清德当局,解放军动手那一刻,“台独”的结局只有1个

梁讯
2026-04-11 08:55:53
少跟孩子生气,因为这一世的相遇,背后藏着你看不见的因果

少跟孩子生气,因为这一世的相遇,背后藏着你看不见的因果

杏花烟雨江南的碧园
2026-04-03 15:15:03
露馅了!阿奇王子奔跑在草地,两年不长高引热议,梅根解释不清

露馅了!阿奇王子奔跑在草地,两年不长高引热议,梅根解释不清

喜欢历史的阿繁
2026-04-10 12:20:39
73岁的普京恐怕没想到,和乌克兰打了四年,最支持他的反而是这国

73岁的普京恐怕没想到,和乌克兰打了四年,最支持他的反而是这国

小小科普员
2026-04-10 16:37:53
外宾级别不一样,入住钓鱼台国宾馆的别墅楼也不一样

外宾级别不一样,入住钓鱼台国宾馆的别墅楼也不一样

贱议你读史
2026-04-11 14:21:16
警惕马奎尔式悲剧!火箭盛赞赵心童天赋:生涯至少四座世锦赛冠军

警惕马奎尔式悲剧!火箭盛赞赵心童天赋:生涯至少四座世锦赛冠军

夜深聊球
2026-04-11 20:21:42
王珞丹现状:搬进深山生活,母亲不再催婚,41岁和两只狗相依为命

王珞丹现状:搬进深山生活,母亲不再催婚,41岁和两只狗相依为命

冷紫葉
2026-04-11 16:48:00
理想汽车CEO李想朋友圈飙脏话后二次发声:怒斥某日系品牌持续拉踩

理想汽车CEO李想朋友圈飙脏话后二次发声:怒斥某日系品牌持续拉踩

快科技
2026-04-11 18:08:11
青岛最有名的十位医生

青岛最有名的十位医生

健身狂人
2026-04-11 08:25:40
为重庆铜梁龙取得领先后,铜梁龙球员陈纯新捂嘴庆祝

为重庆铜梁龙取得领先后,铜梁龙球员陈纯新捂嘴庆祝

懂球帝
2026-04-11 20:50:08
重磅!万科有救了?深圳出手了!

重磅!万科有救了?深圳出手了!

阿离家居
2026-04-11 08:30:11
特朗普连线绕月飞船:讲话后冷场1分钟,宇航员问NASA局长“通话是否中断”

特朗普连线绕月飞船:讲话后冷场1分钟,宇航员问NASA局长“通话是否中断”

红星新闻
2026-04-09 12:44:22
名门千金海清:坐拥9500平大院,给欧豪下跪,儿子被称小谷爱凌

名门千金海清:坐拥9500平大院,给欧豪下跪,儿子被称小谷爱凌

边城少爷
2026-03-21 15:28:36
约30名常驻北约总部的大使级代表将访问日本,专家:欧洲或试图与日本进行深层次防务合作,为兵力调动提前布局

约30名常驻北约总部的大使级代表将访问日本,专家:欧洲或试图与日本进行深层次防务合作,为兵力调动提前布局

极目新闻
2026-04-11 10:35:06
世锦赛战报:中国2领先3落后,常冰玉5连鞭,8-1!下轮对世界冠军

世锦赛战报:中国2领先3落后,常冰玉5连鞭,8-1!下轮对世界冠军

球场没跑道
2026-04-10 20:05:04
随着湖人大胜太阳,掘金赢雷霆,火箭输球,西部前10排名基本确定

随着湖人大胜太阳,掘金赢雷霆,火箭输球,西部前10排名基本确定

球场没跑道
2026-04-11 13:29:35
美伊谈判前夕,卡塔尔突然公开美军“铺路爪”被炸画面,啥意思?

美伊谈判前夕,卡塔尔突然公开美军“铺路爪”被炸画面,啥意思?

兵国大事
2026-04-11 17:14:10
家里有废旧手机的要留意,手机店员工说漏嘴,记得提醒家人朋友

家里有废旧手机的要留意,手机店员工说漏嘴,记得提醒家人朋友

小谈食刻美食
2026-04-02 08:57:37
狂赚4000万欧!巴萨新交易敲定,出售边角料替补,沙特联赛买单

狂赚4000万欧!巴萨新交易敲定,出售边角料替补,沙特联赛买单

祥谈体育
2026-04-11 20:08:17
2026-04-11 21:48:49
固件更新中
固件更新中
有态度网友ytd
1551文章数 16关注度
往期回顾 全部

科技要闻

半夜被燃烧瓶砸醒,OpenAI CEO发文反思

头条要闻

特朗普:美方开始清理霍尔木兹海峡

头条要闻

特朗普:美方开始清理霍尔木兹海峡

体育要闻

换帅之后,他们从降级区冲到升级区

娱乐要闻

郑钧回应儿子走路:会监督他挺直腰板

财经要闻

从日本翻身看:这次谁能扛住高油价?

汽车要闻

焕新极氪007/007GT上市 限时19.39万起

态度原创

时尚
艺术
教育
数码
房产

普通人穿衣其实很简单!构造腰线、一衣多穿,大方舒适又自然

艺术要闻

花6亿,烂尾12年,福建一处“顶奢别墅”,野草都长到三楼了

教育要闻

2026年昆明幼升小 审核材料正在进行中 家长请保持手机畅通!

数码要闻

OPPO ColorOS Watch四月推送升级,这些功能上新了

房产要闻

土地供应突然暴跌!2026海口楼市,格局大变!

无障碍浏览 进入关怀版