← 返回目录

第 15 卷

第 15 / 28 卷日期:

(4)创建自定义 Hook 的注意事项

• 严格遵循 Hook 使用规则:只能在函数组件顶层或其他自定义 Hook 中调用,不可在条件判断、循

环、嵌套函数中调用;

  • 命名必须以 use 开头,否则 React 无法识别为 Hook,ESLint 会报错;

• 自定义 Hook 是逻辑复用,不是组件复用:每个组件调用自定义 Hook 时,内部的内置 Hooks 都

是独立的(如多个组件调用 useRequest,每个组件的 loading、data 状态互不影响);

• 避免过度封装:仅抽取真正复用的逻辑,简单逻辑无需封装为自定义 Hook,否则会增加代码复杂

度;

• 可组合多个自定义 Hook:一个自定义 Hook 内部可调用其他自定义 Hook,实现更复杂的逻辑

(如 useRequest 内部可调用 useLocalStorage 实现请求结果缓存)。

二十六、useCallback 和 useMemo 的区别及其使用场景

1. 核心定义与本质区别

useCallback 和 useMemo 均是 React Hooks 中用于性能优化的工具,核心作用是“缓存”,避免组件重新渲染时重复创建不必要的数据/函数,从而减少子组件不必要的渲染。但两者缓存的目标不同,

这是它们的核心区别:

• useCallback:缓存的是「函数引用」,返回一个记忆化的函数。当组件重新渲染时,若依赖项未

变化,useCallback 返回的函数引用始终不变;若依赖项变化,才会创建新的函数并返回新引用。

• useMemo:缓存的是「函数执行的结果」,返回一个记忆化的值。当组件重新渲染时,若依赖项

未变化,useMemo 直接返回缓存的结果,不会重新执行传入的函数;若依赖项变化,才会重新执行函数并缓存新结果。

补充:两者的语法结构相似,均接收两个参数(回调函数、依赖数组),但用途完全不同,需根据优化目标选择。

2. 语法对比

Code block

1 2// useCallback:缓存函数引用

3const memoizedCallback = useCallback( 4() => {

5// 函数逻辑

11// useMemo:缓存函数执行结果 12const memoizedValue = useMemo(

13() => {

14//需缓存结果的函数逻辑(通常是复杂计算)
15return computeSomething(a, b);
16},
17[a, b] //依赖数组:仅当a或b变化时,才会重新计算结果并缓存
18);

3. 关键区别总结

对比维度useCallbackuseMemo
缓存目标函数引用(避免函数重复创函数执行结果(避免重复计
建)算)
返回值记忆化的函数记忆化的函数执行结果
适用场景优化子组件渲染(避免因函数优化复杂计算(避免组件重新
引用变化导致子组件不必要渲渲染时重复执行耗时计算)

染)

副作用注意内部可包含副作用(但不推必须是纯函数(无副作用),
荐,副作用应放在 useEffect因为执行时机不确定(可能
中)被 React 暂停/恢复)

4. 使用场景详解

(1)useCallback 的使用场景

核心场景:当函数组件需要将函数作为 props 传递给子组件,且子组件通过 React.memo 优化(浅比较 props)时,用 useCallback 缓存函数引用,避免因父组件重新渲染导致函数引用变化,进而触发

子组件不必要的重新渲染。

示例:

Code block

2// 子组件:通过 React.memo 优化,浅比较 props 变化才渲染

9function Parent() { 10const [count, setCount] = useState(0);

11 12// 未使用 useCallback:父组件每次渲染都会创建新的 handleClick 函数,导致 Child 重新

渲染 13// const handleClick = () => { console.log('点击'); };

14

15//使用useCallback:依赖项为空数组,仅初始化时创建一次函数,后续父组件渲染不会变化
16const handleClick = useCallback(() => {
17console.log('点击');
18}, []); //依赖项:无依赖,函数引用永久不变

19 20return (

21<div> 22<p>count: {count}</p>

23<button onClick={() => setCount(count + 1)}>修改count</button>
24<Child onClick={handleClick} name="测试按钮" />
25</div>
26);
27 }

说明:父组件中 count 变化时,父组件会重新渲染。若未使用 useCallback,handleClick 会重新创建,Child 组件的 onClick props 引用变化,即使其他 props 未变,也会触发 Child 重新渲染;使用

useCallback 后,handleClick 引用不变,Child 不会因该函数 props 变化而不必要渲染。

(2)useMemo 的使用场景

核心场景:组件内存在复杂计算(如大数据排序、过滤、多维数据处理),且计算结果仅依赖特定变量,用 useMemo 缓存计算结果,避免组件每次重新渲染时都重复执行耗时计算,提升性能。

示例:

Code block

1 2function DataList() {

3const [list, setList] = useState([1, 3, 2, 5, 4]);
4const [search, setSearch] = useState('');
6//复杂计算:过滤并排序列表(假设list数据量极大,计算耗时)
7//未使用useMemo:组件每次渲染(如search变化、父组件渲染)都会重新执行过滤排序
全站分卷索引 · 28 卷
  1. 1第 1 卷
  2. 2第 2 卷
  3. 3第 3 卷
  4. 4第 4 卷
  5. 5第 5 卷
  6. 6第 6 卷
  7. 7第 7 卷
  8. 8第 8 卷
  9. 9第 9 卷
  10. 10第 10 卷
  11. 11第 11 卷
  12. 12第 12 卷
  13. 13第 13 卷
  14. 14第 14 卷
  15. 15第 15 卷
  16. 16第 16 卷
  17. 17第 17 卷
  18. 18第 18 卷
  19. 19第 19 卷
  20. 20第 20 卷
  21. 21第 21 卷
  22. 22第 22 卷
  23. 23第 23 卷
  24. 24第 24 卷
  25. 25第 25 卷
  26. 26第 26 卷
  27. 27第 27 卷
  28. 28第 28 卷