这是我参与「第四届青训营 」笔记创作活动的第 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。
参考:《如何记忆计算结果?》