react笔记之useCallback

useCallback 是 React 中的一个 Hook,用于缓存函数(callback)的引用 ,避免在组件每次重新渲染时都创建一个新的函数实例


🎯 核心目的:防止不必要的子组件重渲染或重复注册副作用

在 React 中,函数也是值。每次组件重新渲染时,如果直接写 () => {...}function() {...},都会生成一个全新的函数对象。即使函数内容完全一样,JavaScript 也会认为它们是不同的(因为引用不同)。

这在以下场景会带来问题:

  1. 传递给 React.memo 包裹的子组件 → 函数引用变化会导致子组件即使 props 未实质改变也重新渲染。
  2. 作为依赖项传给 useEffectuseMemo 等 Hook → 函数变化会触发不必要的副作用或重新计算。

useCallback 就是用来解决这个问题的。


🔧 语法

js 复制代码
const memoizedCallback = useCallback(
  () => {
    // 函数体
  },
  [dependencies] // 依赖数组
);
  • 只有当依赖数组中的值发生变化时,才会返回一个新的函数
  • 否则,返回之前缓存的函数引用

💡 useCallback(fn, deps) 等价于 useMemo(() => fn, deps)


🌰 举例说明

场景:父组件向子组件传递一个回调函数
js 复制代码
import React, { useState, useCallback } from 'react';

// 子组件用 React.memo 包裹,只有 props 变化才重渲染
const Child = React.memo(({ onIncrement }) => {
  console.log('Child 渲染了');
  return <button onClick={onIncrement}>点我+1</button>;
});

function Parent() {
  const [count, setCount] = useState(0);
  const [name, setName] = useState('');

  // ❌ 没用 useCallback:每次 Parent 渲染都会创建新函数
  // const handleIncrement = () => setCount(c => c + 1);

  // ✅ 使用 useCallback 缓存函数
  const handleIncrement = useCallback(() => {
    setCount(c => c + 1);
  }, []); // 无依赖,只创建一次

  return (
    <div>
      <p>Count: {count}</p>
      <p>
        Name: <input value={name} onChange={e => setName(e.target.value)} />
      </p>
      {/* 传递回调给子组件 */}
      <Child onIncrement={handleIncrement} />
    </div>
  );
}
行为对比:
操作 不用 useCallback 用了 useCallback
修改 name(输入框) Parent 重渲染 → handleIncrement 是新函数 → Child 重渲染(尽管 onIncrement 逻辑没变) handleIncrement 引用不变 → Child 不重渲染
点击按钮 正常工作 正常工作

因为 ChildReact.memo 包裹了,它会浅比较 props。如果 onIncrement 引用变了,就认为 props 变了,于是重渲染。


⚠️ 注意事项

  1. 不要滥用

    如果子组件没有用 React.memo,或者函数不是传给子组件/副作用,那用 useCallback 反而增加开销。

  2. 正确声明依赖

    如果回调里用了状态或 props,必须加到依赖数组中,否则会捕获旧值(stale closure):

    js 复制代码
    const [count, setCount] = useState(0);
    const [step, setStep] = useState(1);
    
    // ❌ 错误:没把 step 加入依赖,永远用初始 step=1
    const increment = useCallback(() => {
      setCount(c => c + step); // step 可能是过期的!
    }, []); // ← 缺少 step
    
    // ✅ 正确
    const increment = useCallback(() => {
      setCount(c => c + step);
    }, [step]);
  3. 它缓存的是"函数引用",不是"执行结果"

    • useMemo → 缓存
    • useCallback → 缓存函数本身

✅ 什么时候该用?

场景 建议使用 useCallback
把函数传给 React.memo 的子组件 ✅ 是
函数作为 useEffect / useMemo 的依赖 ✅ 是
函数只在当前组件内部调用,不传出去 ❌ 否
组件很小,性能不敏感 ❌ 通常不需要

总结一句话:

useCallback 用于稳定函数引用,避免因函数"看似变化"而导致的不必要渲染或副作用,尤其在配合 React.memo 时非常有用。

如果你熟悉 Vue,可以类比:

  • Vue 的方法(methods)天然不会在每次渲染时重建(因为绑定在组件实例上),所以一般不需要类似优化;
  • 而 React 的函数组件每次执行都会重新定义内部函数,所以需要 useCallback 来"冻结"函数引用。
相关推荐
Easonmax2 小时前
基础入门 React Native 鸿蒙跨平台开发:模拟登录注册页面
react native·react.js·harmonyos
三伏5222 小时前
stm32f103系列手册IIC笔记2
笔记·stm32·嵌入式硬件
鄭郑2 小时前
【Playwright学习笔记 06】用户视觉定位的方法
笔记·学习
小二·2 小时前
Python Web 开发进阶实战:AI 伦理审计平台 —— 在 Flask + Vue 中构建算法偏见检测与公平性评估系统
前端·人工智能·python
走粥3 小时前
选项式API与组合式API的区别
开发语言·前端·javascript·vue.js·前端框架
We་ct3 小时前
LeetCode 12. 整数转罗马数字:从逐位实现到规则复用优化
前端·算法·leetcode·typescript
jrlong3 小时前
DataWhale大模型基础与量化微调task4学习笔记(第 1章:参数高效微调_LoRA 方法详解)
笔记·学习
方安乐3 小时前
react笔记之useMemo
前端·笔记·react.js
清风细雨_林木木3 小时前
react 中 form表单提示
前端·react.js·前端框架