一次性认识 useMemo、useCallback 和 memo | 青训营笔记

144 阅读2分钟

这是我参与「第四届青训营 」笔记创作活动的第 8 天

定义

useMemo 和 useCallback

useCallback(fn, deps) 相当于 useMemo(() => fn, deps)

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

官方文档明确说明,你可以把 useMemo 作为一种性能优化的手段,但不要把它当做一种语义上的保证。 它在未来可能会被替代,所以建议代码中即使没有 useMemo 也可以正常工作,另外,如果只是想建立一个不被重新计算的变量,可以 惰性初始化 一个 ref。

使用场景可戳 官方文档 之 如何记忆计算结果?

React.memo

const MyComponent = React.memo(function MyComponent(props) {
  /* 使用 props 渲染 */
});

在 props 不变的情况下,React 将跳过渲染组件的操作并直接复用最近一次渲染的结果。当其内部定义的 state 或 context 发生变化时,它仍会重新渲染。

官方文档明确说明:此方法仅作为 性能优化 的方式而存在。但请不要依赖它来“阻止”渲染,因为这会产生 bug。

使用场景

父组件没有给子组件传 props,组件中的 function 不需要重新定义。

比如这段代码中,Father 组件里有 Child 和 ChildMemo 两个子组件,其中 Child 组件不论是组件本身,还是组件内的方法都没有做任何处理,而 ChildMemo,则使用了 useCallback 和 memo。

初始化

执行子组件内代码(包括定义 function,可以理解为组件重新 render),初始化 ref、state。到这里不论组件是否使用 React.memo 还无任何明显区别。

子组件 state 发生变化

我们点击按钮,给 count+1

  • 普通子组件

    • 即没有使用 React.memo 的组件,组件内代码执行,function 被重新定义(这里不论是箭头函数还是 function 声明的函数都会被重新定义),state 改变。
    • 我们是不希望 function 被重新定义的,因为它并没有任何改动

  • useCallback 子组件

    • 组件重新 render,state 改变。
    • 没有多余的重新定义 function 操作,很棒~

父组件 state 发生变化

我们点击父组件的 +1 按钮,使 state 发生变化

  • 普通子组件
    • 组件重新 render,function 被重新定义。
    • 我们不希望组件重新 render,因为父组件给子组件传递的 props 并没有改变。

  • memo 子组件
    • 无 render 行为,很棒~

结论

useMemo/useCallback 和 memo 确实可以减少不必要的渲染,但正如官方文档所说,它们仅作为 性能优化 的手段存在,不要过度依赖它们,以免出现 bug。

参考:《如何记忆计算结果?》