useEffect 与 useLayoutEffect 有什么区别?
大家好,我是爱吃鱼的桶哥Z。在使用React
开发的过程中,尤其是使用Hook
开发组件,我们需要与后端进行交互的时候,通常我们会在useEffect
这个勾子函数中执行,它与class
组件中的componentDidMount
生命周期函数比较类似,并且它还有一个相近的兄弟--useLayoutEffect
。在面试中经常会问到useEffect
与useLayoutEffect
的区别,以及它们该如何正常使用,那么今天我们就一起来了解一下这两个Hook
之间的区别吧!
useEffect
useEffect
勾子简单来说就是执行一个副作用,那么什么是副作用呢?像我们前面说的,当我们要跟后端进行数据交互时,我们会发起一个请求,而这本书不是React
提供的内容,它就是一个副作用。通常情况下,当我们在useEffect
中执行了某个方法后,当组件卸载的时候,需要在useEffect
中设置一个清除函数将前面使用的方法或者值清除掉,这样可以防止内存的泄漏,如下所示:
useEffect(() => {
const subscription = props.source.subscribe();
return () => {
subscription.unsubscribe();
};
}, []);
在我们使用useEffect
的时候,它的第二个参数可以不传,也可以传一个空数组,或者数组中传值。如果不传任何值,当任意状态发生改变时,组件都会重新渲染;如果传一个空数组,则直接当组件DOM
第一次加载完成后,才执行一次,后续不管任何状态发生改变都不会再执行;如果数组中传入相应的值,则会简单当前值是否发生改变,一旦简单的值发生编写,组件就会重新渲染。
useLayoutEffect
如果看过React
的源码,就会知道useLayoutEffect
与useEffect
内部的实现其实是一样的,唯一不同的点在于useLayoutEffect
在执行的过程中是先调用React
内部的mountLayoutEffect
,然后再调用mountEffectImpl
,而useEffect
执行的时候则是调用的mountEffect
,最后再调用的方法也跟useLayoutEffect
一样。那么mountLayoutEffect
与mountEffect
又有什么不同呢?唯一的不同点也只是触发的时机不同。
useEffect
是异步处理副作用,而useLayoutEffect
是同步处理副作用,什么意思呢?举一个简单的例子,让我们需要修改页面中的DOM
元素的颜色或者位置时,在useEffect
中修改DOM
相关的属性会看到页面有明显的闪动,而在useLayoutEffect
中修改DOM
相关的属性时,则不会发生闪动,这是为什么呢?其实这就是前面说的执行时机的不同。useEffect
能够适用于大部分场景,除了前面的例子中说的修改DOM
元素的位置和颜色这样的场景不适用。而useLayoutEffect
因为是同步执行的,所以在DOM
加载完成后再去进行操作就不会发生闪动,也因为useLayoutEffect
是同步执行的,所以我们也要避免在useLayoutEffect
执行需要大量计算的内容,如果需要大量计算,就会导致页面的卡顿,从而造成页面的阻塞。
我们可以一起看一下上面举的例子,代码如下:
.center {
text-align: center;
margin: 0;
padding: 0;
}
.square {
position: absolute;
top: 50%;
left: 0;
width: 100px;
height: 100px;
background: red;
border-radius: 50%;
}
const Demo = () => {
useEffect(() => {
const square = document.querySelector(".square");
square.style.transform = "translate(-50%, -50%)";
square.style.left = "50%";
square.style.top = "50%";
}, []);
return (
<div className="center">
<div className="square"></div>
</div>
)
};
在DOM
加载的过程中,因为useEffect
是异步执行的,因此当页面渲染完毕后,square
元素会直接从左上角移动到中间位置,导致页面会闪动一下。而当我们将useEffect
替换为useLayoutEffect
后,页面中的圆球就直接在中间展示而不会从左上角偏移过来,具体的效果可以狠戳这里。
最后
useEffect
与useLayoutEffect
的函数签名是完全一致的,从代码角度来说,虽然它们是两个不同的函数,但是它们的使用方法是完全一致的,甚至一定程度上这两者是可以相互替换的,唯一的不同点是它们两的执行时机,并且官方给出的建议是在大部分场景下我们都可以使用useEffect
来完成副作用的执行,只有当useEffect
无法解决时再用useLayoutEffect
进行处理,这样就不会产生相关的性能问题。
最后,如果这篇文章有帮助到你,❤️关注+点赞❤️鼓励一下作者,谢谢大家
往期回顾
转载自:https://juejin.cn/post/7132878706707529759