如何在 React 中正确地使用 useCallback 避免不必要的子组件重新渲染?

如何在 React 中正确地使用 useCallback 避免不必要的子组件重新渲染?

在 React 中,useCallback 是一个用于缓存函数的 Hook,它能防止在每次父组件重新渲染时都创建一个新的函数引用。当把函数作为 prop 传递给子组件(尤其是被 React.memo 包裹的子组件)时,若函数引用发生变化,会导致子组件即使 props 逻辑未变也被重新渲染。

正确使用方式如下:

import React, { useCallback, useState } from 'react';

const Child = React.memo(({ onClick, name }) => {
  console.log('Child rendered');
  return <button onClick={onClick}>Click me: {name}</button>;
});

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

  // 使用 useCallback 缓存函数,仅当 name 改变时才重新创建
  const handleClick = useCallback(() => {
    console.log('Button clicked for', name);
  }, [name]); // 依赖项必须准确

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(c => c + 1)}>Increment</button>
      <Child onClick={handleClick} name={name} />
      <input value={name} onChange={e => setName(e.target.value)} />
    </div>
  );
};

解析:

  • 如果不使用 useCallback,每次 Parent 重新渲染(比如点击 Increment 按钮),handleClick 都会是一个新函数,导致 Child 即使 name 未变也会因 props 引用变化而重新渲染。
  • 使用 useCallback 后,只要依赖项 [name] 没变,handleClick 的引用就不会变,从而避免了 Child 的无效重渲染。
  • 注意:依赖项数组必须包含函数体内使用的所有响应式值(如状态、props 等),否则可能导致闭包陷阱(stale closure)。

此外,useCallback 并非总是必需的。仅在以下情况建议使用:

  1. 子组件使用了 React.memo;
  2. 函数作为 prop 传递给性能敏感的组件;
  3. 函数被用作其他 Hook(如 useEffect)的依赖项。

盲目使用 useCallback 反而可能增加代码复杂度并影响性能(因需比较依赖项)。

发表评论 (审核通过后显示评论):

昵称:
邮箱:
内容: