React-useCallback

核心思想

useCallback 是一个 React Hook,它用于缓存(或称‘记忆化’)一个函数。这能确保在多次重新渲染之间,只要依赖项没有改变,这个函数就不会被重新创建,从而保持其引用的稳定性。


1
2
3
4
5
6
7
8
const memoizedCallback = useCallback(() => {
// 执行逻辑
}, [dependencies]);

// 第一个参数:要记忆的函数
// 第二个参数:依赖数组(dependencies)
// 依赖不变时,返回**同**一个函数引用
// 依赖变化时,才会返回一个**新的**函数引用

为什么需要 useCallback

在 React 中,函数组件每次渲染时都会重新创建函数对象。例如:

1
2
3
4
5
6
7
function MyComponent() {
const handleClick = () => {
console.log("clicked");
};

return <button onClick={handleClick}>Click</button>;
}

这里的 handleClick 每次渲染都会是一个 新的函数对象。如果这个函数作为 props 传给子组件,那么即使逻辑不变,子组件也会认为 props 变了,从而 导致子组件重新渲染。

1
2
3
4
5
6
7
function MyComponent() {
const handleClick = useCallback(() => {
console.log("clicked");
}, []); // 没有依赖,始终返回同一个函数引用

return <button onClick={handleClick}>Click</button>;
}

这样 handleClick 的引用在组件多次渲染时保持不变。


举例对比

❌ 不用 useCallback

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const Parent = () => {
const [count, setCount] = useState(0);

const increment = () => setCount((c) => c + 1);

return (
<div>
<Child onClick={increment} />
<p>{count}</p>
</div>
);
};

const Child = React.memo(({ onClick }) => {
console.log("Child render");
return <button onClick={onClick}>Increment</button>;
});

即使 count 变化,increment 每次都是新函数 → Child 每次都会重新渲染。

✅ 用 useCallback

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const Parent = () => {
const [count, setCount] = useState(0);

const increment = useCallback(() => {
setCount((c) => c + 1);
}, []); // increment 的引用固定

return (
<div>
<Child onClick={increment} />
<p>{count}</p>
</div>
);
};

这样 Child 不会因为函数引用变化而重复渲染,只在必要时更新。