React useMemo、useCallback 和 useRef 的区别和使用场景
请说明 React 中 useMemo、useCallback 和 useRef 三个 Hook 的用途、区别和使用场景。
回答
编译有声
useMemo:缓存计算结果,避免每次渲染都重复计算
// 仅在 deps 变化时重新计算
const total = useMemo(() => expensiveCalc(items), [items]);
// 场景:大数组排序/过滤、复杂计算、缓存 JSX 元素
const children = useMemo(() => <ExpensiveTree data={data} />, [data]);
useCallback:缓存函数引用,避免子组件因回调引用变化而不必要地重渲染
const handleClick = useCallback(() => {
doSomething(id);
}, [id]); // id 不变时,handleClick 引用不变
// 本质:useCallback(fn, deps) === useMemo(() => fn, deps)
// 场景:传递给 React.memo 子组件的回调
useRef:创建可变引用对象,.current 属性在组件的整个生命周期内保持不变
// 1. DOM 引用
const inputRef = useRef(null);
<input ref={inputRef} />;
inputRef.current.focus();
// 2. 存储可变值(变更不触发重渲染)
const countRef = useRef(0);
countRef.current++;
// 3. 保存前一个值
const prevRef = useRef();
useEffect(() => { prevRef.current = count; });
对比总结:
| Hook | 返回值 | 依赖变化时 | 触发重渲染 | 典型用途 |
|---|---|---|---|---|
useMemo | 计算值 | 重新计算 | 否(返回新值) | 性能优化 |
useCallback | 函数 | 重新生成 | 否(返回新函数) | 回调优化 |
useRef | 可变对象 | 不变 | 否 | DOM/变量存储 |
注意:过度使用 useMemo/useCallback 本身也有性能开销,仅在确有必要时使用。