透过源码,理解useCallback与useMemo的妙用
2023-10-11 21:46:14
- 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 可以用于内联回调函数,例如在
onClick
或onChange
事件处理程序中。这可以防止每次组件重新渲染时都创建新的回调函数,从而提高性能。 - 昂贵的函数:useCallback 可以用于昂贵的函数,例如计算密集型函数或网络请求函数。这可以防止这些函数在每次组件重新渲染时都被重新调用,从而提高性能。
- 函数组件:useCallback 可以用于函数组件,例如
PureComponent
或memo
。这可以防止函数组件在每次重新渲染时都创建新的实例,从而提高性能。
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 可以用于内联值,例如在
props
或state
中。这可以防止每次组件重新渲染时都创建新的值,从而提高性能。 - 函数组件:useMemo 可以用于函数组件,例如
PureComponent
或memo
。这可以防止函数组件在每次重新渲染时都创建新的实例,从而提高性能。
3. useCallback 和 useMemo 的区别
useCallback 和 useMemo 都可以用于优化组件的性能,但它们的工作方式略有不同。
- useCallback 返回一个 memoized 的函数,它会在组件重新渲染时被复用。
- useMemo 返回一个 memoized 的值,它会在组件重新渲染时被复用。
因此,useCallback 适用于内联回调函数和昂贵的函数,而 useMemo 适用于昂贵的计算和内联值。
4. 总结
useCallback 和 useMemo 是 React 中用于优化性能的两个钩子。它们可以帮助我们缓存函数或值,从而减少组件的重新渲染。本文通过源码分析的方式,带你深入理解了这两个钩子的工作原理和使用场景。同时,我们还讨论了一些使用技巧,帮助你更好地利用它们来优化你的 React 应用程序。