likes
comments
collection
share

useEffect 与 useLayoutEffect 有什么区别?

作者站长头像
站长
· 阅读数 33

大家好,我是爱吃鱼的桶哥Z。在使用React开发的过程中,尤其是使用Hook开发组件,我们需要与后端进行交互的时候,通常我们会在useEffect这个勾子函数中执行,它与class组件中的componentDidMount生命周期函数比较类似,并且它还有一个相近的兄弟--useLayoutEffect。在面试中经常会问到useEffectuseLayoutEffect的区别,以及它们该如何正常使用,那么今天我们就一起来了解一下这两个Hook之间的区别吧!

useEffect

useEffect勾子简单来说就是执行一个副作用,那么什么是副作用呢?像我们前面说的,当我们要跟后端进行数据交互时,我们会发起一个请求,而这本书不是React提供的内容,它就是一个副作用。通常情况下,当我们在useEffect中执行了某个方法后,当组件卸载的时候,需要在useEffect中设置一个清除函数将前面使用的方法或者值清除掉,这样可以防止内存的泄漏,如下所示:

useEffect(() => {
    const subscription = props.source.subscribe();
    return () => {
        subscription.unsubscribe();
    };
}, []);

在我们使用useEffect的时候,它的第二个参数可以不传,也可以传一个空数组,或者数组中传值。如果不传任何值,当任意状态发生改变时,组件都会重新渲染;如果传一个空数组,则直接当组件DOM第一次加载完成后,才执行一次,后续不管任何状态发生改变都不会再执行;如果数组中传入相应的值,则会简单当前值是否发生改变,一旦简单的值发生编写,组件就会重新渲染。

useLayoutEffect

如果看过React的源码,就会知道useLayoutEffectuseEffect内部的实现其实是一样的,唯一不同的点在于useLayoutEffect在执行的过程中是先调用React内部的mountLayoutEffect,然后再调用mountEffectImpl,而useEffect执行的时候则是调用的mountEffect,最后再调用的方法也跟useLayoutEffect一样。那么mountLayoutEffectmountEffect又有什么不同呢?唯一的不同点也只是触发的时机不同。

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后,页面中的圆球就直接在中间展示而不会从左上角偏移过来,具体的效果可以狠戳这里

最后

useEffectuseLayoutEffect的函数签名是完全一致的,从代码角度来说,虽然它们是两个不同的函数,但是它们的使用方法是完全一致的,甚至一定程度上这两者是可以相互替换的,唯一的不同点是它们两的执行时机,并且官方给出的建议是在大部分场景下我们都可以使用useEffect来完成副作用的执行,只有当useEffect无法解决时再用useLayoutEffect进行处理,这样就不会产生相关的性能问题。

最后,如果这篇文章有帮助到你,❤️关注+点赞❤️鼓励一下作者,谢谢大家

往期回顾

在 React 中为什么要用JSX?

setState 是同步更新还是异步更新?

转载自:https://juejin.cn/post/7132878706707529759
评论
请登录