如何使用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 分钟前
p5.js 掌握圆锥体 cone
前端·数据可视化·canvas
mazhenxiao11 分钟前
qiankunjs 微前端框架笔记
前端
无羡仙18 分钟前
事件流与事件委托:用冒泡机制优化前端性能
前端·javascript
秃头小傻蛋18 分钟前
Vue 项目中条件加载组件导致 CSS 样式丢失问题解决方案
前端·vue.js
CodeTransfer18 分钟前
今天给大家搬运的是利用发布-订阅模式对代码进行解耦
前端·javascript
阿邱吖20 分钟前
form.item接管受控组件
前端
韩劳模22 分钟前
基于vue-pdf实现PDF多页预览
前端
鹏多多23 分钟前
js中eval的用法风险与替代方案全面解析
前端·javascript
KGDragon23 分钟前
还在为 SVG 烦恼?我写了个 CLI 工具,一键打包,性能拉满!(已开源)
前端·svg
LovelyAqaurius23 分钟前
JavaScript中的ArrayBuffer详解
前端