ReactJS
useCallback
useCallback 解决的问题、使用方式和注意事项。
发布于 2026年5月30日0 views
useCallback 用来缓存函数引用。
React 组件每次重新渲染时,组件内部定义的函数都会重新创建。大多数时候这没问题,但如果这个函数被传给 React.memo 包裹的子组件,或者被放进其他 Hook 的依赖数组里,就可能导致额外渲染或重复执行。
解决什么问题
看这个例子:
import { memo, useState } from "react";
const SaveButton = memo(function SaveButton({
onSave,
}: {
onSave: () => void;
}) {
console.log("SaveButton render");
return <button onClick={onSave}>保存</button>;
});
export function Page() {
const [count, setCount] = useState(0);
function handleSave() {
console.log("save");
}
return (
<>
<button onClick={() => setCount((value) => value + 1)}>
{count}
</button>
<SaveButton onSave={handleSave} />
</>
);
}虽然 SaveButton 用了 memo,但每次 Page 重新渲染时,handleSave 都会重新创建。对子组件来说,onSave 是一个新的函数引用,所以 SaveButton 还是会重新渲染。
使用 useCallback:
import { memo, useCallback, useState } from "react";
const SaveButton = memo(function SaveButton({
onSave,
}: {
onSave: () => void;
}) {
console.log("SaveButton render");
return <button onClick={onSave}>保存</button>;
});
export function Page() {
const [count, setCount] = useState(0);
const handleSave = useCallback(() => {
console.log("save");
}, []);
return (
<>
<button onClick={() => setCount((value) => value + 1)}>
{count}
</button>
<SaveButton onSave={handleSave} />
</>
);
}这样只要依赖数组没有变化,handleSave 就会保持同一个函数引用。
使用方式
基本格式:
const fn = useCallback(() => {
// 逻辑
}, [依赖项]);示例:
const handleSearch = useCallback(() => {
fetchUsers(keyword);
}, [keyword]);当 keyword 改变时,handleSearch 会重新创建;如果 keyword 不变,就复用上一次的函数。
适合使用的场景
适合:
- 函数传给了
React.memo子组件。 - 函数作为
useEffect、useMemo等 Hook 的依赖。 - 自定义 Hook 返回函数,希望调用方拿到稳定引用。
- 组件中有比较重的子组件,并且函数 props 导致它频繁重渲染。
不太适合:
- 普通按钮点击函数,没有传给 memo 子组件。
- 函数很简单,组件也很轻。
- 为了“性能优化”给所有函数都包一层
useCallback。
依赖数组
useCallback 的依赖数组很重要。
const handleSubmit = useCallback(() => {
submitForm(form);
}, [form]);函数内部用到了外部变量,就应该放到依赖数组里。否则函数可能拿到旧值。
错误示例:
const handleSubmit = useCallback(() => {
submitForm(form);
}, []);如果 form 会变化,但依赖数组为空,handleSubmit 可能一直使用第一次渲染时的 form。
注意事项
useCallback 不是让函数“不执行”,它只是让函数引用保持稳定。
它不会自动提升业务性能。如果组件本身没有重渲染问题,使用 useCallback 反而会增加理解成本。
还要注意:
- 依赖项必须写对。
- 不要为了消除 lint 提示随便删依赖。
- 如果函数依赖很多状态,先看看状态设计是否可以简化。
useCallback常常和React.memo搭配使用,单独使用不一定有收益。
和 useMemo 的区别
useCallback 缓存函数。
const handleClick = useCallback(() => {
console.log("click");
}, []);useMemo 缓存计算结果。
const total = useMemo(() => {
return price * count;
}, [price, count]);可以简单记:
useCallback(fn, deps)缓存函数。useMemo(() => value, deps)缓存值。
总结
useCallback 解决的是“函数引用每次渲染都变”的问题。它最常见的用途是配合 React.memo,避免函数 props 导致子组件无意义重渲染;使用时重点是写对依赖数组。