如何使用useCallback优化React性能?

JS 基础知识回顾

Javascript中,函数是一种引用类型的变量,即存放的并非真实的值,而是引用值,类似于C语言中的指针类型。

当我们在JavaScript中, 每次定义函数(如 () => {}function() {})时,都会在内存中创建一个新的对象。例如:

Javascript 复制代码
const a = () => {};
const b = () => {};
console.log(a === b); // false(两个不同的函数对象)
  • 关键点 : 函数a和函数b的内容虽然完全相同,但是它们各自创建,代表着内存中的不同位置
  • 结果 : 函数a和函数b实际的值(类似于指针)不一样,因此将它们两相比较的结果就是false

React中函数引用的频繁变化

React中,函数式组件本身就是一个 JavaScript 函数,每次重新渲染时,整个函数体会从头到尾执行一次,包括内部的所有变量和函数声明,组件内部定义的函数会被重新创建,使用新的内存地址。

当父组件将函数通过 props 传递给子组件时,即使函数内容未变,子组件也会因 props 的引用不同而触发重新渲染。

例如,当我们在组件内部定义一个函数时(以 handleClick为例),它本质上是这样工作的:

JSX 复制代码
const Parent = () => {
  // 每次 Parent 渲染时,都会重新声明并创建一个新的 handleClick 函数
  const handleClick = () => {
    console.log("Click");
  };

  return <Child onClick={handleClick} />;
};
  • 关键点:函数组件本身是一个 JavaScript 函数,每次重新渲染时,整个函数体会从头到尾执行一次,包括内部的所有变量和函数声明。
  • 结果handleClick 会被重新创建为一个新的函数对象(新的内存地址),即使函数内容没有变化。不仅如此,每当父组件重新渲染时,Child 就会重新渲染,因为 onClick 的引用变了。

如何解决?用useCallback缓存函数

如果有一种方法,能通过缓存函数,仅在某些条件下(比如依赖项变化时)才生成新函数 ,否则复用上一次的函数引用,那么就可以避免重复创建相同内容的函数引用 。可惜,这只是在白日做梦o (T ヘ To)

事实上,React 中的useCallback钩子就可以帮助我们实现刚才的想法。 通过 useCallback 缓存函数,可以避免每次渲染时重新创建函数:

JSX 复制代码
const Parent = () => {
  // ✅ 用 useCallback 缓存函数,依赖项为空数组(函数只创建一次)
  const handleClick = useCallback(() => {
    console.log("Click");
  }, []);

  return <Child onClick={handleClick} />;
};
  • 关键点handleClick 的引用保持不变,子组件 Childprops 不会发生变化。
  • 结果 :父组件更新 count 时,Child 不会因 onClick 引用变化而重新渲染,从而解决函数引用频繁变化带来的性能问题。

总结

  • 根本问题:函数组件每次渲染时都会重新执行,导致内部函数重新声明。
  • 关键影响:函数引用变化会触发子组件不必要的渲染(即使内容相同)。
  • 解决方案 :用 useCallback 缓存函数,仅在依赖项变化时重新创建函数。

在实际使用时,我们需要清楚何时需要优化函数引用,何时可以直接定义函数。

注意,不要滥用 useCallback,只在必要时使用(如性能敏感场景或子组件依赖函数引用时)。

相关推荐
子兮曰9 小时前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰9 小时前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万10 小时前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝10 小时前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋10 小时前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁11 小时前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
汉堡大王952713 小时前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端
梦想很大很大13 小时前
从运行事实到回归证据:Workrun 的 Telemetry 与 Evaluation 实践
前端·人工智能·后端
计算机魔术师13 小时前
Meta Muse agent 接入 Shopify 的 Shop Pay 实现代理式购物
前端
沙蒿同学14 小时前
我用 Go 搭了一条 AI Agent 流水线:从 1 张商品图到一整套淘宝详情页
前端·javascript·后端