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