jtwang7 / React-Note

React 学习笔记
8 stars 2 forks source link

useMemo vs. useEffect + useState #53

Open jtwang7 opened 2 years ago

jtwang7 commented 2 years ago

useMemo vs. useEffect + useState

参考文章:useMemo vs. useEffect + useState

❇️ 前言

在项目开发中突发奇想有了一个思考:当我们在数据更新触发重渲染的过程中,使用 useMemo 好还是用的比较普遍的 useEffect + useState 好呢?假设我们接收到了一个数据的变动,我们需要在该数据基础上对数据进行重新组织,然后更新视图,则以上两种方法会有各自一套不同的渲染逻辑:

✅ Compare Result

🔆 useEffect + useState 会产生额外的渲染

useEffectuseState 将在每次更改时导致额外的渲染:

举个例子:

function expensiveCalculation(x) { return x + 1; };

我们初始化 x 为 0:

然后,如果我们将 x 更改为 2:

导致 useEffect 二次渲染而 useMemo 不发生二次渲染的原因在于:

❇️ useEffect 发生在页面渲染之后,而 useMemo 则是在页面渲染期间执行。

💡 总结

因此,若只是基于已有值进行改动,并缓存改动后的结果,可以优先考虑 useMemo

useMemo 与 Vue 中的 computed 计算属性使用场景类似,除此之外,他还可以作为一种性能优化的手段。

🔆 useEffect 异步更新

虽然上述场景下 useMemo 看上去是最佳实践,但 useEffect + useState 在某些场景下仍然是较优的一个选择:

在一些长时间运行的同步场景中,useMemo 持有渲染线程,导致用户界面体验卡顿,而 useEffect + useState 是异步运算的,因此不会阻止渲染。

此外,useEffect + useState 可以处理一些带有异步副作用的逻辑,而这些是 useMemo 处理不了的。

参照官方文档说明:传入 useMemo 的函数会在渲染期间执行。请不要在这个函数内部执行不应该在渲染期间内执行的操作,诸如副作用这类的操作属于 useEffect 的适用范畴,而不是 useMemo

所以,当 useMemo 记忆化函数中存在副作用时,我们应当使用 useEffect + useStateuseEffect + useState 在要计算的事物是异步的情况下是正确的解决方案,因为无论如何该值在当前渲染中都不可用。

🔆 useEffectuseMemo 的触发时机

这意味着,useMemo 更紧急,然后是 useLayoutEffect,最后是 useEffect

💡 useEffectuseMemo 触发时机的差异,引出了另一个值得思考的点:相比于 useMemouseEffect 可以获取到更新后的 DOM 节点 (但还未可视化),因此在处理与 DOM 节点有关的操作时更具优势。

❇️ 总结

useEffect + useState

  1. 存在与 DOM 相关的逻辑操作
  2. 大计算量场景
  3. 异步副作用

useMemo

  1. 简单计算
  2. 避免二次重渲染