useCallback的讲解与使用

🧠 一句话解释:

useCallback(fn, deps) 会返回一个 “记住的函数”,只有当依赖项 deps 变化时,才重新创建函数。
这样可以避免每次 render 都生成新的函数引用,从而优化性能、避免子组件重复渲染。

✅ 基本语法

const memoizedFn = useCallback(() => {
  // 函数体
}, [依赖1, 依赖2]);

疑问:

✅ 为什么要用 useCallback?
在 React 中,每次组件渲染时,函数会重新创建:

const handleClick = () => {
  console.log('clicked');
};

每次组件更新时 handleClick 是 新函数,引用变了!
如果你把这个函数传给 React.memo 包裹的子组件:

<Child onClick={handleClick} />

即使 props 看起来没变,因为函数是新引用,子组件也会重新渲染。

✅ 解决方案:

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

🧪 实战例子

const [count, setCount] = useState(0);
const handleClick = useCallback(() => {
  setCount((c) => c + 1);   
/*
等价于
 setCount((prevCount) => {
  return prevCount + 1;
});
因为每次拿到的都是最新的值
*/
}, []); // 不依赖外部变量(闭包中只用 setCount)
return <button onClick={handleClick}>加1</button>;

✅ 何时用 useCallback?

情况------------------------------------------------------|-------------是否推荐用 useCallback
——————————————————————————————————
👎 普通函数只在组件内部使用--------------------|--------------------❌ 不需要
——————————————————————————————————
✅ 函数传给 React.memo 的子组件-------------|--------------------✅ 推荐
——————————————————————————————————
✅ 函数用作 useEffect 的依赖 --------------------|--------------------✅ 推荐
——————————————————————————————————
✅ 函数在频繁渲染的组件中反复定义 ----------|--------------------✅ 推荐
——————————————————————————————————

✅ 对比总结

Hook---------------------------------------------|---------用途
——————————————————————————————————
useState----------------------------------------|-----管理组件内部状态
——————————————————————————————————
useEffect---------------------------------------|------处理副作用(如请求、订阅)
——————————————————————————————————
useRef------------------------------------------|---保存可变值但不引起刷新
——————————————————————————————————
useMemo--------------------------------------|------缓存变量(函数返回值)
——————————————————————————————————
useCallback-----------------------------------|--------缓存函数(避免重新创建函数)
——————————————————————————————————

🧠 总结一句话

useCallback 是用来缓存“函数”的 Hook,特别适合传给子组件或用作依赖,能有效避免不必要的渲染或副作用。

再简单的理解

✅ 用不用的判断方法(秒懂版)
✅ 把函数传给子组件----------------------------需要----------------------------避免子组件无谓刷新
✅ 函数依赖某些值,但你希望它只在值变化时重建----------------------------需要----------------------------保持函数稳定
🚫 函数只在当前组件里用----------------------------不需要----------------------------没有性能问题
🚫 函数不参与复杂逻辑----------------------------不需要----------------------------没必要增加代码复杂度

🧠useCallback那什么时候用了值 但是还可以不加依赖

✅ 合法不加依赖的 3 个常见场景:
✅ 1. 使用函数式更新,不依赖外部变量

const [count, setCount] = useState(0);

const increment = useCallback(() => {
  setCount(prev => prev + 1);  // ✅ 使用了 setState 函数式更新,不依赖外部 count
}, []); // 这里不需要加 count

✅ 2. 值来自 ref,不需要加依赖

const countRef = useRef(0);

const logCount = useCallback(() => {
  console.log(countRef.current);  // ✅ 引用的是 ref,不参与依赖更新
}, []);

📌 说明:
• ref.current 始终是最新值;
• 它不会触发重新渲染;
• 使用 ref 的场景下,不需要加到依赖数组。

✅ 3. 你“只想执行一次”的副作用,故意不加依赖

useEffect(() => {
  console.log('只执行一次');
}, []); // ✅ 故意不加依赖

📌 说明:
• 很多初始化操作只需执行一次(如加载配置、初始化定位);
• 即使用到了外部变量,如果它不会变,这样写也可以;
• 如果 ESLint 警告你,你可以加注释忽略它:

❗什么时候「用了值却不加依赖」会出错?

useEffect(() => {
  if (user.isAdmin) {
    doSomething();
  }
}, []); // ❌ user 其实可能会变
image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容