React中useLayoutEffect钩子使用场景详解
Jovie 人气:0简介
不久前,React对其功能组件进行了一次重大更新(在2019年3月的16.8版本中),终于为这些组件提供了一种变得有状态的方法。
钩子的加入不仅意味着功能组件将能够提供自己的状态,而且还能通过引入useEffect钩子来管理自己的生命周期事件。
此外,这次更新还引入了一个全新的useLayoutEffect钩子,根据React文档,它的作用与[useEffect](upmostly.com/tutorials/i… in a new tab)钩子的作用相当相似;所以这就引出了一个问题。 两者之间到底有什么区别?
如果你对钩子还不熟悉,我建议你去看看 这篇文章在那里你会很好地了解它们是什么,它们的用途,以及你如何在你的应用程序中使用它们。
在这篇文章中,我们将更深入地探讨每个钩子的作用,两者之间的区别是什么,到最后,你应该对它们各自的工作原理有更好的理解,什么时候应该使用其中一个而不是另一个,以及爱上其中一个的一些常见陷阱。
useEffect钩子的概述
这个钩子最初是作为处理功能组件中的副作用的另一种方式添加的,类似于基于类的组件中的componentDidMount和componentDidUpdate方法(它们也是在同一时间运行的)。
因此,它在基于类的组件中的等价物是componentDidMount、componentDidUpdate 和 componentWillUnmount方法的组合,后者是作为参数传递给钩子的回调语句中的一个效果。
钩子流程
- 你以某种方式引起渲染(状态被更新或父类重新渲染)。
- React渲染你的组件(调用它)
- 屏幕得到视觉上的更新
- 然后运行useEffect
useLayoutEffect钩子的概述
与useEffect类似,它与Class Components中的componentDidMount和componentDidUpdate同时运行。然而,useLayoutEffect是同步运行的,与useEffect相反,这意味着它收到的回调只有在组件中进行了V-DOM计算之后,但在它们被绘制到实际的DOM之前才会被调用。
这意味着,如果我们确实需要对任何DOM元素进行任何JavaScript查询,useLayoutEffect是我们可能需要的钩子。
钩子流程
- 你以某种方式导致渲染(改变状态,或者父类重新渲染)。
- React渲染你的组件(调用它)
- useLayoutEffect运行,React等待它完成。
- 屏幕在视觉上被更新
什么时候使用useLayoutEffect钩子?
在使用useEffect钩子时,有一个常见的问题,即当一个组件的状态被更新时,它可能会 "闪动"。这是因为组件在继续进行异步计算的过程中,首先会以部分就绪的状态进行渲染,然后才会以最终的状态进行重新渲染。
这是一个很好的指示,你可能想使用useLayoutEffect钩子来代替。
这样的例子是试图在点击一个按钮时生成并渲染一个极高的数值,就像这个例子中一样:
import { useState, useEffect } from 'react'; import './App.css'; function App() { const [value, setValue] = useState(0); useEffect(() => { if (value === 0) { setValue(10 + Math.random() * 200); } }, [value]); console.log('render', value); return ( <div className="App"> <p>Value: {value}</p> <button onClick={() => setValue(0)}> Generate Random Value </button> </div> ); } export default App;
如果我们要检查我们的应用程序是如何表现的,我们将看到每次我们按下按钮时一个不断变化的闪烁的数字。
状态更新时闪烁的组件
如果我们使用useLayoutEffect钩子,我们就可以摆脱这个视觉错误。
import { useState, useLayoutEffect } from 'react'; import './App.css'; function App() { const [value, setValue] = useState(0); useLayoutEffect(() => { if (value === 0) { setValue(10 + Math.random() * 200); } }, [value]); console.log('render', value); return ( <div className="App"> <p>Value: {value}</p> <button onClick={() => setValue(0)}> Generate Random Value </button> </div> ); } export default App;
而且,你可以从最后一个视频样本中看到,我们已经能够摆脱闪烁的效果了。
这是因为这两个钩子的行为略有不同;第一个钩子是异步处理计算和DOM渲染的,而后者是先进行计算,然后才处理计算结果在屏幕上的渲染。
在我们的例子中,这意味着useEffect钩子正试图生成随机值,并同时将其渲染到屏幕上。另一方面,useLayoutEffect钩子试图首先完成计算,然后才向我们展示生成的数字。
总结
正如你所注意到的,useLayoutEffect钩子为我们提供了一个干净的解决方案,以解决我们可能发现自己经常与之斗争的问题,那就是被React同时处理DOM绘制和计算的方式所纠缠。
作为一个启示,当你在处理 ref 值或需要做任何类型的工作,围绕着通过vanilla JavaScript方法(如querySelector、querySelectorAll或任何其他方式)查询DOM元素时,你可能想使用useLayoutEffect钩。
请记住,尽管useLayoutEffect钩子为我们提供了很多有用的东西,但在99%的情况下,你最好还是使用useEffect钩子,因为它由于其异步的性质,常常会有更高的性能。
所以,就这样了。
希望你现在已经对这两个钩子的用法有了更好的理解,以及每个钩子可能派上用场的场景;这也是特别常见的,因为它被使用得相当少,要么是由于开发者不知道它,要么是知道它,但不确定它的具体作用。
加载全部内容