返回

透过源码,理解useCallback与useMemo的妙用

前端

  1. useCallback

useCallback返回一个 memoized 的函数,它会在组件重新渲染时被复用。这意味着,如果函数的依赖项没有改变,那么它将不会被重新创建。这可以极大地提高性能,尤其是在函数内部有复杂逻辑或计算时。

1.1 useCallback 源码分析

useCallback 的源码位于 react-dom/src/Hooks/useCallback.js 文件中。让我们来看看它的实现:

import {useRef, useEffect} from './useRef';

export function useCallback(callback, deps) {
  const ref = useRef();

  useEffect(() => {
    ref.current = callback;
  }, [callback, ...deps]);

  return () => ref.current;
}

useCallback 通过 useRef 和 useEffect 来实现。它创建一个 ref,用于存储回调函数,并在依赖项数组改变时更新该 ref。当组件重新渲染时,useCallback 会返回 ref.current 中的回调函数。如果依赖项没有改变,ref.current 中的回调函数就不会被重新创建,从而实现了函数的复用。

1.2 useCallback 使用场景

useCallback 可以用于以下场景:

  • 内联回调函数:useCallback 可以用于内联回调函数,例如在 onClickonChange 事件处理程序中。这可以防止每次组件重新渲染时都创建新的回调函数,从而提高性能。
  • 昂贵的函数:useCallback 可以用于昂贵的函数,例如计算密集型函数或网络请求函数。这可以防止这些函数在每次组件重新渲染时都被重新调用,从而提高性能。
  • 函数组件:useCallback 可以用于函数组件,例如 PureComponentmemo。这可以防止函数组件在每次重新渲染时都创建新的实例,从而提高性能。

2. useMemo

useMemo返回一个 memoized 的值,它会在组件重新渲染时被复用。这意味着,如果值的依赖项没有改变,那么它将不会被重新计算。这可以极大地提高性能,尤其是在计算值很复杂或耗时时。

2.1 useMemo 源码分析

useMemo 的源码位于 react-dom/src/Hooks/useMemo.js 文件中。让我们来看看它的实现:

import {useRef, useEffect} from './useRef';

export function useMemo(factory, deps) {
  const ref = useRef();

  useEffect(() => {
    ref.current = factory();
  }, [factory, ...deps]);

  return ref.current;
}

useMemo 通过 useRef 和 useEffect 来实现。它创建一个 ref,用于存储计算结果,并在依赖项数组改变时更新该 ref。当组件重新渲染时,useMemo 会返回 ref.current 中的计算结果。如果依赖项没有改变,ref.current 中的计算结果就不会被重新计算,从而实现了值的复用。

2.2 useMemo 使用场景

useMemo 可以用于以下场景:

  • 昂贵的计算:useMemo 可以用于昂贵的计算,例如计算密集型计算或网络请求。这可以防止这些计算在每次组件重新渲染时都被重新执行,从而提高性能。
  • 内联值:useMemo 可以用于内联值,例如在 propsstate 中。这可以防止每次组件重新渲染时都创建新的值,从而提高性能。
  • 函数组件:useMemo 可以用于函数组件,例如 PureComponentmemo。这可以防止函数组件在每次重新渲染时都创建新的实例,从而提高性能。

3. useCallback 和 useMemo 的区别

useCallback 和 useMemo 都可以用于优化组件的性能,但它们的工作方式略有不同。

  • useCallback 返回一个 memoized 的函数,它会在组件重新渲染时被复用。
  • useMemo 返回一个 memoized 的值,它会在组件重新渲染时被复用。

因此,useCallback 适用于内联回调函数和昂贵的函数,而 useMemo 适用于昂贵的计算和内联值。

4. 总结

useCallback 和 useMemo 是 React 中用于优化性能的两个钩子。它们可以帮助我们缓存函数或值,从而减少组件的重新渲染。本文通过源码分析的方式,带你深入理解了这两个钩子的工作原理和使用场景。同时,我们还讨论了一些使用技巧,帮助你更好地利用它们来优化你的 React 应用程序。