Open jtwang7 opened 2 years ago
参考文章:useMemo vs. useEffect + useState
在项目开发中突发奇想有了一个思考:当我们在数据更新触发重渲染的过程中,使用 useMemo 好还是用的比较普遍的 useEffect + useState 好呢?假设我们接收到了一个数据的变动,我们需要在该数据基础上对数据进行重新组织,然后更新视图,则以上两种方法会有各自一套不同的渲染逻辑:
useMemo
useEffect + useState
useState
setState()
useEffect
useMemo callback
useEffect 和 useState 将在每次更改时导致额外的渲染:
举个例子:
function expensiveCalculation(x) { return x + 1; };
我们初始化 x 为 0:
x
然后,如果我们将 x 更改为 2:
导致 useEffect 二次渲染而 useMemo 不发生二次渲染的原因在于:
❇️ useEffect 发生在页面渲染之后,而 useMemo 则是在页面渲染期间执行。
因此,若只是基于已有值进行改动,并缓存改动后的结果,可以优先考虑 useMemo
useMemo 与 Vue 中的 computed 计算属性使用场景类似,除此之外,他还可以作为一种性能优化的手段。
computed
虽然上述场景下 useMemo 看上去是最佳实践,但 useEffect + useState 在某些场景下仍然是较优的一个选择:
在一些长时间运行的同步场景中,useMemo 持有渲染线程,导致用户界面体验卡顿,而 useEffect + useState 是异步运算的,因此不会阻止渲染。
此外,useEffect + useState 可以处理一些带有异步副作用的逻辑,而这些是 useMemo 处理不了的。
参照官方文档说明:传入 useMemo 的函数会在渲染期间执行。请不要在这个函数内部执行不应该在渲染期间内执行的操作,诸如副作用这类的操作属于 useEffect 的适用范畴,而不是 useMemo。
所以,当 useMemo 记忆化函数中存在副作用时,我们应当使用 useEffect + useState。useEffect + useState 在要计算的事物是异步的情况下是正确的解决方案,因为无论如何该值在当前渲染中都不可用。
useEffect 是一个集体调用,无论是否异步,它是在所有组件渲染后收集的。
useLayoutEffect是一个集体调用,但它同步发生在页面渲染更新前。
useLayoutEffect
useMemo 是一个本地调用,它只与这个组件有关。可以将 useMemo 视为一个具有使用上次更新结果的赋值语句。
这意味着,useMemo 更紧急,然后是 useLayoutEffect,最后是 useEffect。
💡 useEffect 和 useMemo 触发时机的差异,引出了另一个值得思考的点:相比于 useMemo ,useEffect 可以获取到更新后的 DOM 节点 (但还未可视化),因此在处理与 DOM 节点有关的操作时更具优势。
useMemo vs. useEffect + useState
参考文章:useMemo vs. useEffect + useState
❇️ 前言
在项目开发中突发奇想有了一个思考:当我们在数据更新触发重渲染的过程中,使用
useMemo
好还是用的比较普遍的useEffect + useState
好呢?假设我们接收到了一个数据的变动,我们需要在该数据基础上对数据进行重新组织,然后更新视图,则以上两种方法会有各自一套不同的渲染逻辑:useEffect + useState
:用useState
重新创建一个变量来维护更新后的数据,将原数据处理完毕后setState()
存入到该变量中并触发重渲染,useEffect
捕获到依赖项发生变化,基于新数据更新视图。useMemo
:基于 callbcak 返回一个值作为变量进行维护,同时提供一个依赖数组选项,当依赖选项发生改变时,会同步触发useMemo callback
重新计算并更新变量。✅ Compare Result
🔆
useEffect + useState
会产生额外的渲染useEffect
和useState
将在每次更改时导致额外的渲染:举个例子:
我们初始化
x
为 0:useMemo
版本会立即呈现 1,因为它基于 x 进行初始化并同步更新数据然后,如果我们将 x 更改为 2:
useMemo
运行并呈现 3useEffect
版本运行,再次渲染 1,然后效果触发,组件以正确的值 3 重新运行。导致
useEffect
二次渲染而useMemo
不发生二次渲染的原因在于:❇️
useEffect
发生在页面渲染之后,而useMemo
则是在页面渲染期间执行。💡 总结
useEffect
版本会导致两倍的渲染量,这对性能不利。useMemo
版本更简洁、更易读。它不会引入不必要的可变状态,并且移动部件更少。因此,若只是基于已有值进行改动,并缓存改动后的结果,可以优先考虑
useMemo
🔆
useEffect
异步更新虽然上述场景下
useMemo
看上去是最佳实践,但useEffect + useState
在某些场景下仍然是较优的一个选择:在一些长时间运行的同步场景中,
useMemo
持有渲染线程,导致用户界面体验卡顿,而useEffect + useState
是异步运算的,因此不会阻止渲染。此外,
useEffect + useState
可以处理一些带有异步副作用的逻辑,而这些是useMemo
处理不了的。所以,当
useMemo
记忆化函数中存在副作用时,我们应当使用useEffect + useState
。useEffect + useState
在要计算的事物是异步的情况下是正确的解决方案,因为无论如何该值在当前渲染中都不可用。🔆
useEffect
与useMemo
的触发时机useEffect
是一个集体调用,无论是否异步,它是在所有组件渲染后收集的。useLayoutEffect
是一个集体调用,但它同步发生在页面渲染更新前。useMemo
是一个本地调用,它只与这个组件有关。可以将useMemo
视为一个具有使用上次更新结果的赋值语句。💡
useEffect
和useMemo
触发时机的差异,引出了另一个值得思考的点:相比于useMemo
,useEffect
可以获取到更新后的 DOM 节点 (但还未可视化),因此在处理与 DOM 节点有关的操作时更具优势。❇️ 总结
useEffect + useState
useMemo