我试图在网上找到一个简洁的答案,但没有运气。
关于useEffect
、useMemo
和useState
之间的差异,以下是否正确?
useState
和useMemo
都会记住跨渲染的值。区别在于:useMemo
不会导致重新渲染,而useState
会导致重新渲染useMemo
仅在其依赖项(如果有)发生更改时运行,而setSomeState
(useState
返回的第二个数组项)没有这样的依赖项数组
useMemo
和useEffect
仅在其依赖项更改(如果有)时运行。区别在于:useEffect
在渲染发生后运行,而useMemo
在渲染发生之前运行
我错过了任何其他关键差异吗?
你的观点基本上是正确的,一些小的澄清:
useState导致在调用 setState 方法(返回的数组中的第二个元素)时重新呈现。它没有任何依赖关系,如useMemo或useEffect。
useMemo仅在其依赖数组中的元素发生变化时才重新计算值(如果没有依赖关系 - 即数组为空,它只会重新计算一次)。如果省略数组,它将在每次渲染时重新计算。调用该函数不会导致重新呈现。此外,它在组件渲染期间而不是之前运行。
useEffect在每次渲染后调用,如果其依赖数组中的元素已更改或数组被遗漏。如果阵列为空,则只会在初始装载时运行一次(如果返回清理函数,则卸载)。
您可以随时查看 Hooks API 参考,在我看来,这是一个非常可靠的文档
useEffect(callback, [dependency])
的返回值是void
并在render()
之后执行。useMemo(callback, [dependency])
的返回值不是void
而是记忆值,它在render()
期间执行。
在以下情况下,useEffect()
可以提供与useMemo()
相同的优化:
- 昂贵的计算中使用的状态变量(即 count1)是 useImpact 的唯一依赖项。
- 当我们不介意将昂贵的计算值存储在状态变量中时。
const [count1, setCount1] = useState(0);
const [expensiveValue, setExpensiveValue] = useState(null);
useEffect(() => {
console.log("I am performing expensive computation");
setExpensiveValue(((count1 * 1000) % 12.4) * 51000 - 4000);
}, [count1]);
- 唯一的区别是,
useEffect()
使昂贵的计算值在render()
后可用,而useMemo()
使值在render()
期间可用。 - 大多数情况下,这并不重要,因为如果该值已计算用于在UI中呈现,则
useEffect()
和useMemo()
都将在浏览器完成绘制之前使该值可用。
useMemo
用于记忆属于组件但不一定属于组件状态的计算/值,例如验证、依赖组件且必须返回值的方法;
const validEmail = React.useMemo(() => validateEmail(email), [email])
/* Now use 'validEmail' variable across the component,
whereas 'useEffect' return value is void and only used for unmounting duties,
like unsubscribing from subscription e.g. removeInterval*/
从文档:
<小时 />请记住,传递给 useMemo 的函数在渲染期间运行。不要在那里做任何渲染时通常不会做的事情。例如,副作用属于useEffect,而不是useMemo。
useEffect
副作用:
突变、订阅、计时器、日志记录和 其他副作用
setState
的setTimeout
setInterval
ref
分配、API 调用或任何不执行繁重计算的东西都属于这里。
还要记住,优化是有代价的,因此 React 建议仅在需要记忆/优化时才使用useMemo
,在其他情况下,在必要时依赖useEffect
:
您可以依赖 useMemo 作为性能优化,而不是语义保证。
将来,React 可能会选择"忘记"一些以前记住的 值并在下次渲染时重新计算它们,例如释放内存 屏幕外组件。编写代码,使其在没有的情况下仍然可以工作 useMemo — 然后添加它以优化性能。
[state, setState] = useState()
即更新给定的状态变量,该变量在重新渲染期间保持稳定,并调用附加到它setState
触发重新渲染。这个钩子的目的与上述两个钩子没有太大关系。