跳到主要内容

认识

2023年02月22日
柏拉文
越努力,越幸运

一、介绍


useCallback 用于缓存函数,当组件重现渲染时不会重新创建该函数(防止父组件重新渲染导致函数引用发生变化)

二、语法


const cachedFn = useCallback(fn, dependencies)
  • fn: 想要缓存的函数。此函数可以接受任何参数并且返回任何值。React 将会在初次渲染而非调用时返回该函数。当进行下一次渲染时,如果 dependencies 相比于上一次渲染时没有改变,那么 React 将会返回相同的函数。否则,React 将返回在最新一次渲染中传入的函数,并且将其缓存以便之后使用。React 不会调用此函数,而是返回此函数。你可以自己决定何时调用以及是否调用。

  • dependencies: 有关是否更新 fn 的所有响应式值的一个列表。响应式值包括 propsstate

  • cachedFn: 在初次渲染时,useCallback 返回你已经传入的 fn 函数。在之后的渲染中, 如果依赖没有改变,useCallback 返回上一次渲染中缓存的 fn 函数;否则返回这一次渲染传入的 fn

三、用法


四、对比


4.1 useCallback 实现原理?

useCallback 用于缓存函数,当组件重现渲染时不会重新创建该函数(防止父组件重新渲染导致函数引用发生变化)

Mount 阶段: 调用 mountCallback, 创建一个 Hook 对象, 存储在 当前处理的 fiber.memoizedState 中。Hook 对象中也有一个 memoizedState, 用于存储函数和依赖项。最后返回函数。

Update 阶段: 从当前的 Fiber 中取出 Hook 链表, 依次循环遍历执行, 执行到 useCallback 链时, 执行 updateCallback, 通过 Object.is 循环对比依赖项数组, 如果依赖项中的每一项依赖都没有发生变化, 则不做任何处理。如果发生变化, 重新存储函数和依赖项, 返回函数。

4.2 useCallback 和 useMemo 有什么区别?

useMemo 缓存传入函数执行的返回值, 根据依赖项重新计算结果, 类似于 Vue 中的 Computed。而 useCallback 缓存传入的函数, 防止父组件重新渲染导致函数引用发生变化。

4.3 useCallback()、useMemo() 有什么缺陷? 可以滥用吗?

useMemouseCallback 基于依赖项缓存函数返回值或者函数本身, 如果依赖项设置不当, 可能会存在闭包问题, 可能会导致缓存的数据不更新或者产生错误的引用。而且, React 对渲染方面做了很多优化, 比如 bailout 或者 eagerState 等, 过多使用 useMemo 或者 useCallback 会使代码变得臃肿, 同时也没有带来实际的性能收益, 而且缓存过多的函数或计算结果可能会导致内存占用增加。因此, 当你需要将某个函数传递给子组件,而子组件依赖于 referential equality(比如 React.memoshouldComponentUpdate 中的比较)时,使用 useCallback 是有意义的。