useCallback
和 useMemo
是 React 中用于性能优化的两个核心 Hook,它们的核心区别在于缓存的内容和使用场景:
1. 核心区别
特性 | useCallback | useMemo |
---|---|---|
缓存内容 | 缓存函数(函数引用) | 缓存计算结果(值) |
语法 | useCallback(fn, deps) |
useMemo(() => value, deps) |
主要用途 | 避免子组件因父组件重新渲染而无效更新 | 避免重复计算昂贵的值 |
2. 使用场景
useCallback
-
传递回调函数给子组件 :当子组件被
React.memo
包裹时,父组件传递的函数引用变化会导致子组件重新渲染。useCallback
可确保函数引用稳定。iniconst handleClick = useCallback(() => { // 逻辑 }, [依赖项]); <ChildComponent onClick={handleClick} />
-
依赖项作为其他 Hook 的参数 :例如
useEffect
或另一个useCallback
,需确保依赖函数稳定。scssuseEffect(() => { fetchData(handleSuccess); // handleSuccess 需稳定 }, [handleSuccess]);
useMemo
-
复杂计算结果缓存:如大数据处理、格式转换等,避免每次渲染重复计算。
iniconst filteredData = useMemo(() => { return data.filter(item => item.price > 100); }, [data]);
-
优化引用类型变量:如对象、数组,避免因引用变化触发子组件渲染。
iniconst config = useMemo(() => ({ theme: "dark" }), []);
3. 关键注意事项
-
依赖数组:必须完整列出所有依赖项,否则可能导致闭包问题或无效缓存。
scss// 错误示例:依赖项缺失可能导致旧值引用 const value = useMemo(() => data.value, []); // 应 [data]
-
避免滥用:过度使用会增加内存开销,仅对性能敏感场景使用。
-
与
React.memo
配合 :useCallback
常与React.memo
联用,优化组件渲染链。
4. 性能对比示例
useCallback 场景
ini
// 父组件
const Parent = () => {
const [count, setCount] = useState(0);
const increment = useCallback(() => {
setCount(c => c + 1);
}, []); // 函数引用稳定
return <Child onIncrement={increment} />;
};
// 子组件(React.memo)
const Child = React.memo(({ onIncrement }) => {
// 仅在 onIncrement 变化时重新渲染
return <button onClick={onIncrement}>+</button>;
});
useMemo 场景
javascript
const ExpensiveComponent = ({ data }) => {
const result = useMemo(() => {
// 复杂计算(如排序、过滤)
return data.sort((a, b) => a.value - b.value);
}, [data]); // 数据变化时才重新计算
return <div>{result}</div>;
};
5. 总结
- useCallback:缓存函数引用,优化子组件渲染。
- useMemo:缓存计算结果,避免重复计算。
- 共同原则:仅在必要时使用,依赖数组需完整,避免内存泄漏。