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

WHAT - useCallback 深入理解

文章目录

  • 一句话理解
  • 场景 1:防止子组件不必要的重新渲染
  • 场景 2:在 `useEffect` 中依赖一个函数
  • 场景 3:结合自定义 Hook 传入回调
  • 场景 4:配合 `useMemo` / 复杂计算逻辑
  • 场景 5:与性能优化库结合(例如虚拟列表、表格)
  • 注意事项
  • 总结

在 WHAT - React 函数与 useMemo vs useCallback 我们简单了解过 useCallback。今天我们来深入理解一下。

useCallback 是 React 中一个非常重要但容易被误解的 Hook。今天我们通过 多个典型场景 来理解它的用途和原理。


一句话理解

useCallback(fn, deps) 会返回一个 记忆化(缓存)版本的回调函数
只有当依赖项 (deps) 变化时,才会返回新的函数引用。


场景 1:防止子组件不必要的重新渲染

这是最常见的场景。

问题

当父组件重新渲染时,所有在它内部定义的函数都会被重新创建。

import React, { useState } from 'react';const Child = React.memo(({ onClick }: { onClick: () => void }) => {console.log('✅ Child render');return <button onClick={onClick}>Click me</button>;
});export default function App() {const [count, setCount] = useState(0);const handleClick = () => console.log('clicked');return (<div><p>Count: {count}</p><button onClick={() => setCount(count + 1)}>+1</button><Child onClick={handleClick} /></div>);
}

👉 每次点击“+1”,父组件重新渲染,handleClick 被重新创建(函数引用变了)。
即使 Child 用了 React.memo,它也会重新渲染,因为 onClick 变了。


解决:使用 useCallback

const handleClick = useCallback(() => console.log('clicked'), []);

✅ 现在 handleClick 的引用在依赖 [] 不变时保持稳定。
父组件更新时,Child 不会重新渲染。


场景 2:在 useEffect 中依赖一个函数

如果你把函数直接写在组件里,而又在 useEffect 中依赖它,会导致无限循环。

useEffect(() => {fetchData();
}, [fetchData]); // 🚨 fetchData 每次都是新函数,会导致无限请求

✅ 使用 useCallback 固定函数引用:

const fetchData = useCallback(() => {// fetch something
}, []);useEffect(() => {fetchData();
}, [fetchData]); // ✅ 不会无限循环

场景 3:结合自定义 Hook 传入回调

例如在一个自定义 Hook 里需要外部传一个回调。

function useEventListener(event: string, handler: () => void) {useEffect(() => {window.addEventListener(event, handler);return () => window.removeEventListener(event, handler);}, [event, handler]);
}

⚠️ 如果 handler 每次都是新函数(没用 useCallback),
那每次渲染都会移除再添加一次事件监听。

✅ 改用:

const handleKeyDown = useCallback(() => {console.log('Pressed key');
}, []);useEventListener('keydown', handleKeyDown);

场景 4:配合 useMemo / 复杂计算逻辑

比如你在一个 memoized 的计算中依赖一个回调:

const computeValue = useCallback((x: number) => x * 2, []);
const result = useMemo(() => computeValue(10), [computeValue]);

这样可以确保 computeValue 不会频繁变化导致 useMemo 重新计算。


场景 5:与性能优化库结合(例如虚拟列表、表格)

像 Ant Design Table、react-window 等组件会用到 onRow, onClick, rowRenderer 等回调。
如果不使用 useCallback,每次渲染都会创建新的函数,造成性能浪费或无法缓存。

const onRowClick = useCallback((record) => {console.log('Clicked row:', record);
}, []);

注意事项

  1. 不是所有函数都要用 useCallback

    • 它会增加内存开销和心智负担。

    • 一般只在以下场景使用:

      • 函数传给 React.memo 的子组件;
      • 函数作为 useEffect 依赖;
      • 函数传给性能敏感组件(虚拟列表、大表格等)。
  2. 依赖数组很重要!

    • 若函数中引用了外部状态变量,必须把它们加进依赖数组中。
    const handleClick = useCallback(() => {console.log(count);
    }, [count]); // ✅ count 是依赖
    
  3. useCallback(fn, deps)useMemo(() => fn, deps)

    • 本质上 useCallbackuseMemo 的一个语法糖。

总结

场景是否适合用 useCallback说明
子组件 props 是函数且使用 React.memo避免子组件重复渲染
函数放在 useEffect 依赖中避免无限循环
自定义 Hook 接受回调避免重复副作用
函数只在本组件使用没必要缓存
简单 onClick/onChange直接写即可

如果你愿意,我可以帮你写一个 交互式 demo(计数器 + 子组件 + useCallback对比)
让你在浏览器里实时看到差异。
是否要我帮你写一个这样的例子?

http://www.dtcms.com/a/573947.html

相关文章:

  • 怎么做自己的网站推广淘宝客怎么样做自己的网站
  • 网站建设大师程序员给别人做的网站违法
  • 文件属性获取与目录IO操作详解
  • 优秀网站首页广东省建设注册中心网站
  • 要将ITP集成到Jenkins Pipeline中,实现开发发版时自动触发自动化测试
  • Linux 定时监测 Java 服务
  • 体外产品的研发网站如何建设paypal网站做外贸
  • 浙江城乡建设局和住建局seo课程培训入门
  • 3系统需求调研项目整合管理
  • Nestjs框架: Consul健康检查与gRPC客户端动态管理优化方案
  • 开机自动启动activity
  • 医学图像分割评价指标Dice与HD95的详解
  • 杀毒软件杀毒原理(草稿)
  • 网站开发需要会的东西网页设计大赛主题
  • 如何将iPhone上的笔记传输到电脑
  • 发布公司信息的网站网推接单
  • MES 离散制造核心流程详解(含关键动作、角色与异常处理)
  • 网站建设方案与报价wordpress文章怎么生成标签
  • 雄安投资建设集团网站东莞网站建设咨询
  • ruoyi前端(vue3)框架,切换菜单白屏问题
  • HTML5+CSS3小实例:不用JS实现幽灵网格动画
  • 人工智能 机器学习 深度学习
  • 用C++从零开始实现的小型深度学习训练框架
  • 算法题(Python)数组篇 | 3.有序数组的平方
  • 网站引流怎么做广告海报图片
  • 专业人士怎样建网站超星网站开发实战答案
  • 做推广的网站那个好网路营销网站策划书
  • muduo库学习(1):Reactor模型的设计思想
  • 分布式ID|从源码角度深度解析美团Leaf双Buffer优化方案
  • 【UE·优化篇】使用FramePro优化UI性能