useCallback

  1. const memoizedCallback = useCallback(
  2. () => {
  3. doSomething(a, b);
  4. },
  5. [a, b],
  6. );

返回一个 memoized 回调函数。

memoized函数 记忆函数(Memoization)是一种用于长递归或长迭代操作性能优化的编程实践。
记忆函数实现原理:使用一组参数初次调用函数时,缓存参数和计算结果,当再次使用相同的参数调用该函数时,直接返回相应的缓存结果。

注意: 记忆化函数不能有副作用。不然的话,再次调用这个函数,得到的结果可能会不一样。

useCallback返回的memoized回调函数的意思是:当useCallback的依赖项没有发生变化的时候,返回的memoizedCallback函数就不会有变化。

  1. let a: () => void
  2. // ref是确定的一个
  3. const A: ForwardRefRenderFunction<HTMLHeadingElement> = (props, ref) => {
  4. const time = useTimer(3, 1000)
  5. const b = useCallback(() => {
  6. console.log('我是timeCallBack', a)
  7. return a
  8. }, [])
  9. console.log(a, b, a === b)
  10. a = b
  11. return (
  12. <>
  13. <h1 ref={ref}>time:{time}</h1>
  14. <button type="button" onClick={b}>
  15. 改变title
  16. </button>
  17. </>
  18. )
  19. }

useTimer是一个定时器的自定义hooks。由于这里的useCallBack什么也不依赖,所以,始终返回的是相同的b函数。这样的话,除了第一次aundefined的情况,后序的都是true的结果。

现在再来看官网的解释:

返回一个 memoized 回调函数。

把内联回调函数及依赖项数组作为参数传入 useCallback,它将返回该回调函数的 memoized 版本,该回调函数仅在某个依赖项改变时才会更新。当你把回调函数传递给经过优化的并使用引用相等性去避免非必要渲染(例如 shouldComponentUpdate)的子组件时,它将非常有用。

所以这是优化,子组件的不必要渲染的一个优化的hooks。在子组件中:

  1. 类组件使用shouldComponetUpdate或者pureComponent
  2. 函数组件使用memo高阶组件。

但是都是props的浅比较。使用的都是Object.is算法。

useMemo

  1. const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

返回一个 memoized 值。

与useCallback一样,只要依赖项不变,返回的memoizedValue也就不会变,一般是用于返回引用类型。

把“创建”函数和依赖项数组作为参数传入 useMemo,它仅会在某个依赖项改变时才重新计算 memoized 值。这种优化有助于避免在每次渲染时都进行高开销的计算。

记住,传入 useMemo 的函数会在渲染期间执行。请不要在这个函数内部执行与渲染无关的操作,诸如副作用这类的操作属于 useEffect 的适用范畴,而不是 useMemo。

如果没有提供依赖项数组,useMemo 在每次渲染时都会计算新的值。
例如:

  1. const b = useMemo(() => ({ a: 1 }), undefined)

如果第二个值传递undefined的话,每次返回的b都是通过回调函数得到的新b。所以说,如果实在是没有依赖什么值的话,写一个空数组。

很类似于Vue的compouted。得到的值依赖另一些值,如果另一些值没有发生变化的话,那么如果渲染几次,都是得到同样的结果。

而且还有一点就是:如果每次渲染当前函数组件的话,useMemo里面的回调的是否执行(返回值是否是同一个)也是依赖于第二个参数的。