【译】不用每个地方都用memo, useMemo, useCallback

一、简单介绍memoization

阅读此译文前,需要了解一下memoization(记忆化/备忘化)

【译】不用每个地方都用memo, useMemo, useCallback

维基百科这样描述:

在计算机领域,记忆化或备忘化是一种优化技术,主要用于加快计算机程序的速度,通过存储昂贵的函数调用的结果,并在相同的输入再次出现时返回缓存的结果。

(英文解释: 维基百科-Memoization)

简言之,memoization通过内存来提升速度(以空间换速度),会影响应用程序的性能。这意味着只在某些场景下(处理繁重的纯函数)适用,不可滥用。

二、译文

一方面,如果你的应用程序和这个网站(react新文档)一样,很多交互都是粗粒度的(例如替换一个页面或者整个区域),那么通常都没必要memoize。另一方面,如果你的应用程序更像一个图形编辑器,大部分交互都是细粒度的(像移动形状),那么你可能会发现memoization非常有用。

1. 你应该用memo包裹每个组件吗?

【译】不用每个地方都用memo, useMemo, useCallback

[原文地址: Should you add memo everywhere? ]

只有当你的组件使用完全相同的props频繁地重新渲染,且重新渲染的逻辑复杂时,使用memo优化才有价值。如果当你的组件重新渲染时没有明显的延迟,那么memo是不必要的。请记住,如果传递给组件的 props 始终不同(例如你传递的对象或纯函数是在渲染期间定义的),则memo完全无用。这就是你经常需要同时使用 memouseMemouseCallback 的原因。

在其他情况下,用memo包裹组件没有任何好处。


2. 你应该到处使用useMemo吗?

【译】不用每个地方都用memo, useMemo, useCallback

[原文地址: Should you add useMemo everywhere? ]

只有在以下几种情况下,使用useMemo优化才有价值:

① 你使用 useMemo 进行的计算明显很慢,并且它的依赖很少变化。

② 你将其作为prop传递给一个包裹在memo中的组件。如果该值没有更改,你想跳过重新渲染。memoization让你的组件只在依赖发生变化时重新渲染。

③ 你传递的值将会被用作某个Hook的依赖。例如,也许另一个useMemo计算值依赖于它。或者也许你的useEffect依赖于它。

在其他情况下,用useMemo包裹计算结果没有任何好处。

那样做也没有太大的危害,因此一些团队选择不考虑个别情况,尽可能地memoize。这种方案的缺点是代码变得不太可读。此外,并不是所有的memoization都是有效的:一个“永远是新的”的单一值就足以破坏整个组件的memoization


3. 你应该到处使用useCallback吗?

【译】不用每个地方都用memo, useMemo, useCallback

[原文地址: Should you add useCallback everywhere? ]

只有在以下几种情况下,使用 useCallback 缓存函数才有价值:

① 你将其作为prop传递给一个包裹在memo中的组件。如果该值没有更改,你想跳过重新渲染。memoization让你的组件只在依赖发生变化时重新渲染。

② 你传递的函数将会被用作某个Hook的依赖。例如,另一个包裹在useCallback 中的函数依赖于它,或者也许你的useEffect依赖于它。

那样做也没有太大的危害,因此一些团队选择不考虑个别情况,尽可能地memoize。这种方案的缺点是代码变得不太可读。此外,并不是所有的memoization都是有效的:一个“永远是新的”的单一值就足以破坏整个组件的memoization

请注意,useCallback 不能阻断创建函数。你总是要创建一个函数(这很好!),但 React 忽略它,如果依赖没有改变,就会给你返回一个缓存的函数。


4. 总结:如何避免大量使用memoization

在实践中,你可以通过遵循以下原则来避免大量使用memoization

  • ① 当一个组件在视觉上包裹其他组件时,让它接收 JSX 作为子组件。这样,当父组件更新自己的状态时,React知道它的子组件不需要重新渲染。

  • ② 优先使用本地状态,不要将状态提升到不必要的层级。例如,不要将短暂状态(如表单和鼠标是否悬停某元素)保留在树的顶部或全局状态库中。

  • ③ 保持你的渲染逻辑是纯的。如果重新渲染组件引起了问题或产生一些明显的视觉效果,则是你组件中的 bug!修复 bug 而不是添加memoization

  • ④ 避免使用不必要的effect来更新状态。React 应用程序中的大多数性能问题都是因为 Effects 链使组件反复渲染。

  • ⑤ 尝试从effect中删除不必要的依赖。例如,与其使用memoization,不如将某些对象或函数移动到effect内部或组件外部。

如果某些交互仍然感觉很卡顿,请使用React Developer Tools分析器查看哪些组件将从memoization中获益最多,并在需要时添加memoization。这些原则使你的组件更易于调试和理解,因此在任何情况下都遵循它们都是不会出错的。从长远来看,我们正在研究自动进行粒度memoization以一劳永逸地解决这个问题。

【译】不用每个地方都用memo, useMemo, useCallback

三. 拓展阅读

  1. useCallback/useMemo 的使用误区
  2. 【译】你真的应该使用 useMemo 吗? 让我们一起来看看
  3. 了解 JavaScript 中的 Memoization 以提高性能,再看 React 的应用

原文链接:https://juejin.cn/post/7214378356686913597 作者:蓝瑟

(0)
上一篇 2023年3月26日 下午5:26
下一篇 2023年3月26日 下午5:36

相关推荐

发表回复

登录后才能评论