Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >useLayoutEffect和useEffect执行时机有什么不同

useLayoutEffect和useEffect执行时机有什么不同

原创
作者头像
beifeng1996
发布于 2022-12-07 01:12:42
发布于 2022-12-07 01:12:42
1.5K00
代码可运行
举报
文章被收录于专栏:前端面试前端面试
运行总次数:0
代码可运行

我们先看下 React 官方文档对这两个 hook 的介绍,建立个整体认识

useEffect(create, deps):

该 Hook 接收一个包含命令式、且可能有副作用代码的函数。在函数组件主体内(这里指在 React 渲染阶段)改变 DOM、添加订阅、设置定时器、记录日志以及执行其他包含副作用的操作都是不被允许的,因为这可能会产生莫名其妙的 bug 并破坏 UI 的一致性。使用 useEffect 完成副作用操作。赋值给 useEffect 的函数会在组件渲染到屏幕之后执行。你可以把 effect 看作从 React 的纯函数式世界通往命令式世界的逃生通道。

useLayoutEffect(create, deps):

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

注意加粗的字段,React 官方的文档其实把两个 hook 的执行时机说的很清楚,下面我们深入到 react 的执行流程中来理解下

问题

  • useEffect 和 useLayoutEffect 的区别?
  • useEffect 和 useLayoutEffect 哪一个与 componentDidMount,componentDidUpdate 的是等价的?
  • useEffect 和 useLayoutEffect 哪一个与 componentWillUnmount 的是等价的?
  • 为什么建议将修改 DOM 的操作里放到 useLayoutEffect 里,而不是 useEffect?

流程

  1. react 在 diff 后,会进入到 commit 阶段,准备把虚拟 DOM 发生的变化映射到真实 DOM 上
  2. 在 commit 阶段的前期,会调用一些生命周期方法,对于类组件来说,需要触发组件的 getSnapshotBeforeUpdate 生命周期,对于函数组件,此时会调度 useEffect 的 create destroy 函数
  3. 注意是调度,不是执行。在这个阶段,会把使用了 useEffect 组件产生的生命周期函数入列到 React 自己维护的调度队列中,给予一个普通的优先级,让这些生命周期函数异步执行
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 可以近似的认为,React 做了这样一步,实际流程中要复杂的多

setTimeout(() => {
      const preDestory = element.destroy;
      if (!preDestory) prevDestroy();
      const destroy = create();
      element.destroy= destroy;
}, 0);
  1. 随后,就到了 React 把虚拟 DOM 设置到真实 DOM 上的阶段,这个阶段主要调用的函数是 commitWork,commitWork 函数会针对不同的 fiber 节点调用不同的 DOM 的修改方法,比如文本节点和元素节点的修改方法是不一样的。
  2. commitWork 如果遇到了类组件的 fiber 节点,不会做任何操作,会直接 return,进行收尾工作,然后去处理下一个节点,这点很容易理解,类组件的 fiber 节点没有对应的真实 DOM 结构,所以就没有相关操作
  3. 但在有了 hooks 以后,函数组件在这个阶段,会同步调用上一次渲染时 useLayoutEffect(create, deps) create 函数返回的 destroy 函数
  4. 注意一个节点在 commitWokr 后,这个时候,我们已经把发生的变化映射到真实 DOM 上了
  5. 但由于 JS 线程和浏览器渲染线程是互斥的,因为 JS 虚拟机还在运行,即使内存中的真实 DOM 已经变化,浏览器也没有立刻渲染到屏幕上
  6. 此时会进行收尾工作,同步执行对应的生命周期方法,我们说的componentDidMount,componentDidUpdate 以及 useLayoutEffect(create, deps) 的 create 函数都是在这个阶段被同步执行
  7. 对于 react 来说,commit 阶段是不可打断的,会一次性把所有需要 commit 的节点全部 commit 完,至此 react 更新完毕,JS 停止执行
  8. 浏览器把发生变化的 DOM 渲染到屏幕上,到此为止 react 仅用一次回流、重绘的代价,就把所有需要更新的 DOM 节点全部更新完成
  9. 浏览器渲染完成后,浏览器通知 react 自己处于空闲阶段,react 开始执行自己调度队列中的任务,此时才开始执行 useEffect(create, deps) 的产生的函数

解答

useEffect 和 useLayoutEffect 的区别?

useEffect 在渲染时是异步执行,并且要等到浏览器将所有变化渲染到屏幕后才会被执行。

useLayoutEffect 在渲染时是同步执行,其执行时机与 componentDidMount,componentDidUpdate 一致

对于 useEffect 和 useLayoutEffect 哪一个与 componentDidMount,componentDidUpdate 的是等价的?

useLayoutEffect,因为从源码中调用的位置来看,useLayoutEffect的 create 函数的调用位置、时机都和 componentDidMount,componentDidUpdate 一致,且都是被 React 同步调用,都会阻塞浏览器渲染。参考 前端进阶面试题详细解答

useEffect 和 useLayoutEffect 哪一个与 componentWillUnmount 的是等价的?

同上,useLayoutEffect 的 detroy 函数的调用位置、时机与 componentWillUnmount 一致,且都是同步调用。useEffect 的 detroy 函数从调用时机上来看,更像是 componentDidUnmount (注意React 中并没有这个生命周期函数)。

为什么建议将修改 DOM 的操作里放到 useLayoutEffect 里,而不是 useEffect?

可以看到在流程9/10期间,DOM 已经被修改,但但浏览器渲染线程依旧处于被阻塞阶段,所以还没有发生回流、重绘过程。由于内存中的 DOM 已经被修改,通过 useLayoutEffect 可以拿到最新的 DOM 节点,并且在此时对 DOM 进行样式上的修改,假设修改了元素的 height,这些修改会在步骤 11 和 react 做出的更改一起被一次性渲染到屏幕上,依旧只有一次回流、重绘的代价。

如果放在 useEffect 里,useEffect 的函数会在组件渲染到屏幕之后执行,此时对 DOM 进行修改,会触发浏览器再次进行回流、重绘,增加了性能上的损耗。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
useEffect与useLayoutEffect
useEffect与useLayoutEffect可以统称为Effect Hook,Effect Hook可以在函数组件中执行副作用操作,副作用是指函数或者表达式的行为依赖于外部环境,或者在这里可以理解为修改了某状态会对其他的状态造成影响,这个影响就是副作用,数据获取,设置订阅以及手动更改React组件中的DOM都属于副作用。
WindRunnerMax
2022/05/06
1.2K0
关于useEffect的一切
对于浏览器环境来说,只有渲染器会执行类似appendChild、insertBefore这样的DOM操作。
公众号@魔术师卡颂
2020/09/01
1.1K0
何时在 React 中使用 useEffect 和 useLayoutEffect
React Hooks,在 React 16.8 中引入,彻底改变了我们在 React 中编写组件的方式。它们允许我们在不编写类的情况下使用状态和其他 React 功能。其中的两个钩子,useEffect 和 useLayoutEffect,用于在函数组件中执行副作用。但是应该在什么情况下使用它们各自呢?让我们探索一下这两个钩子并找出答案。
zayyo
2023/11/29
2880
react源码解析10.commit阶段
在render阶段的末尾会调用commitRoot(root);进入commit阶段,这里的root指的就是fiberRoot,然后会遍历render阶段生成的effectList,effectList上的Fiber节点保存着对应的props变化。之后会遍历effectList进行对应的dom操作和生命周期、hooks回调或销毁函数,各个函数做的事情如下
全栈潇晨
2021/06/10
4440
精准解析 useLayoutEffect 与 useEffect 的执行时机
我们前面花了大量篇幅,从基础、理论、实践、总结几个方面,全方位的为大家分析了 useEffect。除此之外,React 还提供了一个与 useEffect 几乎一样的 hook,它就是
用户6901603
2023/12/14
4710
精准解析 useLayoutEffect 与 useEffect 的执行时机
2022前端必会的面试题(附答案)
服务端渲染是数据与模版组成的html,即 HTML = 数据 + 模版。将组件或页面通过服务器生成html字符串,再发送到浏览器,最后将静态标记"混合"为客户端上完全交互的应用程序。页面没使用服务渲染,当请求页面时,返回的body里为空,之后执行js将html结构注入到body里,结合css显示出来;
goClient1992
2022/07/26
2.2K0
前端一面react面试题总结
mobx相对来说⽐较简单,在其中有很多的抽象,mobx更多的使⽤⾯向对象的编程思维;redux会⽐较复杂,因为其中的函数式编程思想掌握起来不是那么容易,同时需要借助⼀系列的中间件来处理异步和副作⽤
beifeng1996
2023/01/06
2.9K0
社招前端一面react面试题汇总
在 super() 被调用之前,子类是不能使用 this 的,在 ES2015 中,子类必须在 constructor 中调用 super()。传递 props 给 super() 的原因则是便于(在子类中)能在 constructor 访问 this.props。
goClient1992
2022/09/13
3K0
React Hooks源码浅析
前段时间研究了一波React的渲染流程,内部机制的源码,阅读到一半的时候React终于推出了16.8.x的版本,主要带来的更新就是Hooks的新功能。相信已经有很多的使用教程或者源码阅读文章。那么我也来一个属于自己的阅读有感的文章,做一个记录吧。
LamHo
2022/09/26
1.9K0
React Hooks源码浅析
useLayoutEffect和useEffect的区别
大家面试的过程中有没有遇到过这样的问题呢,useLayoutEffect和useEffect的区别是什么,大家可能会回答useEffect是异步的,useLayoutEffect是同步的,这样回答面试官真的会满意慢,我们需要说清楚他们在源码中的调用时机。
长腿程序员165858
2022/12/19
4040
面试官:useLayoutEffect和useEffect的区别
hello,这里是潇晨,大家面试的过程中有没有遇到过这样的问题呢,useLayoutEffect和useEffect的区别是什么,大家可能会回答useEffect是异步的,useLayoutEffect是同步的,这样回答面试官真的会满意慢,我们需要说清楚他们在源码中的调用时机。
全栈潇晨
2021/12/15
1.7K0
React Hooks 源码解析(4):useEffect
React 源码版本: v16.11.0 源码注释笔记:airingursb/react 1. useEffect 简介 1.1 为什么要有 useEffect 我们在前文中说到 React Hooks 使得 Functional Component 拥有 Class Component 的特性,其主要动机包括: 在组件之间复用状态逻辑很难 复杂组件变得难以理解 难以理解的 class 对于第二点,首先,针对 Class Component 来说,我们写 React 应用时经常要在组件的各种生命周期中编
QQ音乐前端团队
2019/12/24
2.4K0
React Hooks 源码解析(4):useEffect
react高频面试题总结(一)
那为什么会有这样的限制呢?Hooks 的设计初衷是为了改进 React 组件的开发模式。在旧有的开发模式下遇到了三个问题。
helloworld1024
2022/08/02
1.4K0
[OHIF-Viewers]医疗数字阅片-医学影像-REACT-Hook API索引
如果你刚开始接触 Hook,那么可能需要先查阅 Hook 概览。你也可以在 Hooks FAQ 章节中获取有用的信息。
landv
2020/07/09
2.1K0
前端面试指南之React篇(二)
在shouldComponentUpdate 这个方法中,这个方法主要用来判断是否需要调用render方法重绘DOM
beifeng1996
2022/11/02
2.9K0
React 进阶 - lifecycle
React 类组件为开发者提供了一些生命周期钩子函数,能让开发者在 React 执行的重要阶段,在钩子函数里做一些该做的事。自从 React Hooks 问世以来,函数组件也能优雅地使用 Hooks ,弥补函数组件没有生命周期的缺陷。
Cellinlab
2023/05/17
9010
React 进阶 - lifecycle
【React Hooks 专题】useEffect 使用指南
Hooks 是 React 16.8 的新增特性,至今经历两年的时间,它可以让你在不编写 class 组件的情况下使用 state 以及其他 React 特性。useEffect 是基础 Hooks 之一,我在项目中使用较为频繁,但总有些疑惑 ,比如:
清秋
2022/09/20
2.6K0
【React Hooks 专题】useEffect 使用指南
百度前端一面高频react面试题指南_2023-02-23
简言之,HOC是一种组件的设计模式,HOC接受一个组件和额外的参数(如果需要),返回一个新的组件。HOC 是纯函数,没有副作用。
用户10358021
2023/02/23
2.9K0
【React】945- 你真的用对 useEffect 了吗?
useEffect 做了什么? 通过使用这个 Hook,你可以告诉 React 组件需要在渲染后执行某些操作。React 会保存你传递的函数(我们将它称之为 “effect”),并且在执行 DOM 更新之后调用它。在这个 effect 中,我们设置了 document 的 title 属性,不过我们也可以执行数据获取或调用其他命令式的 API。
pingan8787
2021/05/14
9.7K0
【React】945- 你真的用对 useEffect 了吗?
前端二面react面试题整理
每个React组件强制要求必须有一个 render()。它返回一个 React 元素,是原生 DOM 组件的表示。如果需要渲染多个 HTML 元素,则必须将它们组合在一个封闭标记内,例如 <form>、<group>、<div> 等。此函数必须保持纯净,即必须每次调用时都返回相同的结果。
beifeng1996
2022/12/19
1.1K0
相关推荐
useEffect与useLayoutEffect
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验