- 基本概念
useCallback: 缓存函数useMemo: 缓存值
- 语法对比
// useCallback
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
);
// useMemo
const memoizedValue = useMemo(
() => computeExpensiveValue(a, b),
[a, b]
);
- 主要区别
useCallback返回一个记忆化的函数useMemo返回一个记忆化的值useCallback(fn, deps)相当于useMemo(() => fn, deps)
- 使用场景
useCallback 适用场景:
// 父组件
function Parent() {
const [count, setCount] = useState(0);
// 不使用 useCallback
const handleClick = () => {
console.log('clicked');
};
// 使用 useCallback
const handleClickMemoized = useCallback(() => {
console.log('clicked');
}, []); // 空依赖数组,函数永远不会改变
return (
<div>
<Child onClickHandler={handleClickMemoized} />
<button onClick={() => setCount(count + 1)}>Update Count</button>
</div>
);
}
// 子组件
const Child = React.memo(({ onClickHandler }) => {
console.log("Child rendered");
return <button onClick={onClickHandler}>Click me</button>;
});
useMemo 适用场景:
function ExpensiveComponent({ data }) {
// 复杂计算的结果被缓存
const processedData = useMemo(() => {
return data.map(item => {
// 假设这是一个复杂的计算
return expensiveOperation(item);
});
}, [data]); // 只有当 data 改变时才重新计算
return (
<div>
{processedData.map(item => (
<div key={item.id}>{item.value}</div>
))}
</div>
);
}
- 性能优化建议
- 不要过度使用这些 hooks,只在确实需要优化性能时使用
- 合理设置依赖数组
- 配合
React.memo使用效果更好
- 常见陷阱
// ❌ 错误使用
function Component() {
const [count, setCount] = useState(0);
// 这种简单计算没必要使用 useMemo
const doubleCount = useMemo(() => count * 2, [count]);
// 这种简单函数没必要使用 useCallback
const handleClick = useCallback(() => {
setCount(count + 1);
}, [count]);
}
// ✅ 正确使用
function Component({ onItemsChange, items }) {
// 复杂计算使用 useMemo
const sortedItems = useMemo(() => {
return [...items].sort((a, b) => b.priority - a.priority);
}, [items]);
// 传递给子组件的回调函数使用 useCallback
const handleChange = useCallback((newItems) => {
const processed = someExpensiveOperation(newItems);
onItemsChange(processed);
}, [onItemsChange]);
}
- 性能影响
- 过度使用这些 hooks 可能会导致内存使用增加
- 在简单场景下使用反而会因为创建缓存而降低性能
- 应该在以下情况使用:
- 计算量大的操作(useMemo)
- 需要保持引用相等的回调函数(useCallback)
- 作为 props 传递给使用 React.memo 的子组件的函数
这个问题很好地体现了 React 性能优化的核心概念,也是实际开发中经常需要考虑的问题。理解这两个 hooks 的区别和适用场景,对于编写高性能的 React 应用至关重要。