likes
comments
collection
share

用过useEffect,useLayoutEffect吗

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

前言

之前做一个需求,发现存在二次渲染的情况。在这里记录一下useEffectuseLayoutEffect的区别

先看一段代码

用过useEffect,useLayoutEffect吗

打印顺序是什么? 各位小伙伴可以先自行猜想一下。

useEffect

官方定义

在函数组件主体内(这里指在 React 渲染阶段)改变 DOM、添加订阅、设置定时器、记录日志以及执行其他包含副作用的操作都是不被允许的,因为这可能会产生莫名其妙的 bug 并破坏 UI 的一致性。

通俗点来说

useEffect 其实就是让函数组件拥有了生命周期。

useEffect的执行时机

官方定义

与 componentDidMountcomponentDidUpdate 不同的是,传给 useEffect 的函数会在浏览器完成布局与绘制之后,在一个延迟事件中被调用。这使得它适用于许多常见的副作用场景,比如设置订阅和事件处理等情况,因为绝大多数操作不应阻塞浏览器对屏幕的更新。

通俗点来讲

不论在面试中,还是工作中。如果有人问你useEffect是如何模拟生命周期的。你都会不假思索的回答出

  • 第二个参数传递一个空数组, 模拟componentDidMount

  • 第二个参数传递依赖项,模拟componentDidUpdate

  • 第二个参数传递一个空数组,并且里面通过return的形式去调用一个方法,模拟componentWillUnmount

但是useEffect的执行顺序问题,你有想到吗?如果父组件和子组件同时存在useEffect究竟是谁先走?

看一段代码

用过useEffect,useLayoutEffect吗

结果

用过useEffect,useLayoutEffect吗

为什么子组件的useEffect先走?

分析

我们都值得useEffect的执行是在commit之后,React的commit阶段是干什么的?简单来说,就是将DOM渲染到页面上。那么我们是否可以想到,useEffect其实是在页面已经渲染结束后,再触发的?

按照这个执行逻辑来看的话:

  • 父组件进入commit阶段,发现有Son组件需要渲染。

  • 开始进行Son的生命周期, Son进入commit阶段,执行子组件的useEffectSon渲染结束

  • 父组件进行commit阶段,渲染完成,执行useEffect

useLayoutEffect

官方定义

其函数签名与 useEffect 相同,但它会在所有的 DOM 变更之后同步调用 effect。可以使用它来读取 DOM 布局并同步触发重渲染。在浏览器执行绘制之前,useLayoutEffect 内部的更新计划将被同步刷新

通俗来讲

useLayoutEffectcomponentDidMount是同步执行的。在commit阶段之前执行,执行顺序优于useEffect

用过useEffect,useLayoutEffect吗

执行顺序

用过useEffect,useLayoutEffect吗

useEffect 与 useLayoutEffect 的区别

useEffect 更改值

  • 好处不阻塞浏览器屏幕的渲染更新

  • 坏处 会造成二次渲染,用户体验不佳

用过useEffect,useLayoutEffect吗

不会做动图。。。。各位大佬自己试一下。。。

会闪烁一下,页面首先展示的是初始值,点击初始值,先更改为我改变了,再更改为我又改变了? 对用户的体验很不好。

useLayoutEffect 更改值

  • 好处componentDidMount同步执行,不会造成二次渲染

  • 坏处 可能会阻塞浏览器屏幕的渲染更新

用过useEffect,useLayoutEffect吗

页面首先展示的是初始值,点击初始值,更改为我又改变了

最初代码的执行图

用过useEffect,useLayoutEffect吗

可能理解比较浅。后续有更好的理解会修改此文