useEffect与useLayoutEffect

useEffectuseLayoutEffect可以统称为Effect HookEffect Hook可以在函数组件中执行副作用操作,副作用是指函数或者表达式的行为依赖于外部环境,或者在这里可以理解为修改了某状态会对其他的状态造成影响,这个影响就是副作用,数据获取,设置订阅以及手动更改React组件中的DOM都属于副作用。

useEffect

useEffect Hook可以看做 componentDidMountcomponentDidUpdatecomponentWillUnmount这三个生命周期函数的组合,但是使用多个Effect实现关注点分离,也就是说useEffect的粒度更低,可以将各个关注的位置分离处理副作用。

既然是对componentDidMountcomponentDidUpdatecomponentWillUnmount这三个生命周期函数的组合,那么我们也可以使用useEffect将其分离,首先对于componentDidMountcomponentWillUnmount,也就是想执行只运行一次的 effect(仅在组件挂载和卸载时执行),由于不存在任何依赖,那么对于第二个参数就是一个空的数组。如果省略了第二个参数的话,那么在组件的初始化和更新都会执行,一般情况下是并不希望这样的,因为Hooks的设计,每次setState都会重新执行组件函数,这样的话副作用函数就会频繁执行,所以通常来说还是尽量不要省略第二个参数。回到生命周期,通常如果在组件建立时建立了一个定时器,那么我们希望在组件销毁的时候将定时器销毁来避免内存泄露,那么在useEffect中返回一个函数调用去关闭定时器即可,在这里我们的关注点可以集中在一起而不用再分开两个生命周期去写了。

import { useEffect, useState } from "react";
import "./styles.css"; export default function App() {
const [count, setCount] = useState(0); useEffect(() => {
console.log("Component is mounted");
return () => console.log("Component is unmounted");
}, []); useEffect(() => {
console.log("Component is mounted or updated");
}) return (
<div>
<div>{count}</div>
<button onClick={() => setCount(count + 1)}>count + 1</button>
</div>
);
}

对于componentDidUpdate,之前如果是写class组件实现相同的功能的话,就需要在这个生命周期中嵌入很多的逻辑,使用useEffect就可以将各个关注点分离,分别处理其副作用,当然如果依然需要解除诸如订阅或者定时器等,依旧可以返回一个处理函数来处理。

import { useEffect, useState } from "react";
import "./styles.css"; export default function App() {
const [count, setCount] = useState(0); useEffect(() => {
console.log("Count is updated");
document.title = `count: ${count}`;
}, [count]); return (
<div>
<div>{count}</div>
<button onClick={() => setCount(count + 1)}>count + 1</button>
</div>
);
}

在文档中还指出请确保数组中包含了所有外部作用域中会随时间变化并且在effect中使用的变量,否则你的代码会引用到先前渲染中的旧变量。如果你传入了一个空数组[]effect内部的propsstate就会一直拥有其初始值。下面这个例子就会出现一个bug,在依赖数组中没有传递count,那么就会导致当effect执行时,创建的effect闭包会将count的值保存在该闭包当中,且初值为0,每隔一秒回调就会执行setCount(0 + 1),因此count永远不会超过1,此时如果我们将count加入到依赖数组中便可解决这个问题。对于这个问题,React提供了一个exhaustive-depsESLint规则作为eslint-plugin-react-hooks包的一部分,它会帮助你找出无法一致地处理更新的组件。

import { useEffect, useState } from "react";
import "./styles.css"; export default function App() {
const [count, setCount] = useState(0); useEffect(() => {
const id = setInterval(() => {
setCount(count + 1);
console.log(count + 1);
}, 1000);
return () => clearInterval(id);
}, []); // `count` 没有被指定为依赖 return (
<div>
<div>{count}</div>
<button onClick={() => setCount(count + 1)}>count + 1</button>
</div>
);
}

看起来和VueWatch很像,但是又不尽然相同,语法上的区别主要就在于useEffect可以监控多个属性的变化,Watch不行,当然Watch可以通过间接的方式实现,但是思想方面是不同的,Vue是监听值的变化而React是用以处理副作用。提到这个的主要原因是因为之前写Vue较多,就老想着通过Vue的角度来类比React的各项实现,感觉这样有好处也有弊端,好处就是很快能够上手,坏处就是很容易钻牛角尖,或者很容易陷入一个围城。有位大佬说的挺好的,你需要把Vue忘掉再来学习Hooks,虽然并不绝对但也很有道理。

当函数组件刷新渲染时,包含useEffect的组件整个运行过程如下:

  • 触发组件重新渲染,通过改变组件state或者组件的父组件重新渲染,导致子节点渲染。
  • 组件函数执行。
  • 组件渲染后呈现到屏幕上。
  • useEffect hook执行。

useLayoutEffect

useLayoutEffectuseEffect很像,函数签名也是一样,唯一的不同点就是useEffect是异步执行,而useLayoutEffect是同步执行的。当函数组件刷新渲染时,包含useLayoutEffect的组件整个运行过程如下:

  • 触发组件重新渲染,通过改变组件state或者组件的父组件重新渲染,导致子组件渲染。
  • 组件函数执行。
  • useLayoutEffect hook执行,React等待useLayoutEffect的函数执行完毕。
  • 组件渲染后呈现到屏幕上。

每日一题

https://github.com/WindrunnerMax/EveryDay

参考

https://zhuanlan.zhihu.com/p/348701319
https://zhuanlan.zhihu.com/p/259766064
https://segmentfault.com/a/1190000039087645
http://www.ptbird.cn/react-hoot-useEffect.html
https://react.docschina.org/docs/hooks-effect.html
https://pengfeixc.com/blog/605af93600f1525af762a725
https://react.docschina.org/docs/hooks-faq.html#is-it-safe-to-omit-functions-from-the-list-of-dependencies

useEffect与useLayoutEffect的更多相关文章

  1. React的useEffect与useLayoutEffect执行机制剖析

    引言 useEffect和useLayoutEffect是React官方推出的两个hooks,都是用来执行副作用的钩子函数,名字类似,功能相近,唯一不同的就是执行的时机有差异,今天这篇文章主要是从这两 ...

  2. useEffect 和 useLayoutEffect浅析

    执行时期的区别 useEffect 回调函数的执行时期 useEffect为异步执行,执行时期为 触发状态更新(如:setState,forceUpdate) React渲染函数执行(render) ...

  3. React中useLayoutEffect和useEffect的区别

    重点: 1.二者函数签名相同,调用方式是一致的 2. 怎么简单进行选择: 无脑选择useEffect,除非运行效果和你预期的不一致再试试useLayoutEffect 区别详解:useEffect是异 ...

  4. 精读《setState 做了什么》

    1 引言 setState 是 React 框架最常用的命令,它是用来更新状态的,这也是 React 框架划时代的功能. 但是 setState 函数是 react 包导出的,他们又是如何与 reac ...

  5. Preact(React)核心原理详解

    原创: 宝丁 玄说前端 本文作者:字节跳动 - 宝丁 一.Preact 是什么 二.Preact 和 React 的区别有哪些? 三.Preact 是怎么工作的 四.结合实际组件了解整体渲染流程 五. ...

  6. React Hooks用法大全

    前言 在 React 的世界中,有容器组件和 UI 组件之分,在 React Hooks 出现之前,UI 组件我们可以使用函数,无状态组件来展示 UI,而对于容器组件,函数组件就显得无能为力,我们依赖 ...

  7. React源码 commit阶段详解

    转: React源码 commit阶段详解 点击进入React源码调试仓库. 当render阶段完成后,意味着在内存中构建的workInProgress树所有更新工作已经完成,这包括树中fiber节点 ...

  8. PReact10.5.13源码理解之hook

    hook源码其实不多,但是实现的比较精巧:在diff/index.js中会有一些optison.diff这种钩子函数,hook中就用到了这些钩子函数.   在比如options._diff中将curr ...

  9. react之react Hooks

    函数组件,没有 class 组件中的 componentDidMount.componentDidUpdate 等生命周期方法,也没有 State,但这些可以通过 React Hook 实现. Rea ...

  10. ahooks 中那些控制“时机”的hook都是怎么实现的?

    本文是深入浅出 ahooks 源码系列文章的第五篇,该系列已整理成文档-地址.觉得还不错,给个 star 支持一下哈,Thanks. 本文来探索一下 ahooks 是怎么封装 React 的一些执行& ...

随机推荐

  1. JMS微服务开发示例(五)生成短token,实现用户无状态登录

    用户token,也可以利用第三方框架生成,JMS也包含了自己的token服务器. 部署TokenServer 到这里下载 tokenserver.zip,然后部署运行TokenServer. 微服务中 ...

  2. [转帖]SQL Server索引的维护 - 索引碎片、填充因子

    https://www.cnblogs.com/kissdodog/archive/2013/06/14/3135412.html 这两个问题都和页密度有关,虽然两者的表现形式在本质上有所区别,但是故 ...

  3. [转帖]【最佳实践】prometheus 监控 sql server (使用sql_exporter)

    https://www.cnblogs.com/gered/p/13535212.html 目录 [0]核心参考 [简述] [1]安装配置 sql_exporter [1.1]下载解压 sql_exp ...

  4. [转帖]【SOP】最佳实践之 TiDB 业务写变慢分析

    https://zhuanlan.zhihu.com/p/647831844 前言 在日常业务使用或运维管理 TiDB 的过程中,每个开发人员或数据库管理员都或多或少遇到过 SQL 变慢的问题.这类问 ...

  5. [转帖]TiFlash 源码阅读(一) TiFlash 存储层概览

    https://cloud.tencent.com/developer/article/1988629 背景 本系列会聚焦在 TiFlash 自身,读者需要有一些对 TiDB 基本的知识.可以通过这三 ...

  6. [转帖]一文浅析Nginx线程池!

    https://zhuanlan.zhihu.com/p/616500765     Nginx通过使用多路复用IO(如Linux的epoll.FreeBSD的kqueue等)技术很好的解决了c10k ...

  7. 你还在“垃圾”调优?快来看看JDK17的ZGC如何解放双手 | 京东云技术团队

    1.前言 不要犹豫了,GC最大停顿时间小于1ms,支持16TB内存,这么高的性能提升,也不需要复杂的调优,节省了这个时间,你去陪对象不香嘛. 上篇文章给大家带来了JDK11升级JDK17的最全实践,相 ...

  8. 浅浅的源码剖析grpc-go(一)

    最近在学习 rpc 相关的知识,如果让我去从头设计一个 rpc,我从使用者的角度出发,究竟需要去做一下什么工作? 第一,RPC 本质上就是一个远程调用,那肯定就需要通过网络来传输数据.虽然传输协议可以 ...

  9. 大模型应用开发:为产品创建一个AI客服/智能助手

    欢迎阅读本系列文章!我将带你一起探索如何使用OpenAI API来开发GPT应用.无论你是编程新手还是资深开发者,都能在这里获得灵感和收获. 本文将继续展示AI助手的开发方式,在OpenAPI中它的名 ...

  10. Go复合类型之数组类型

    Go复合类型之数组 @ 目录 Go复合类型之数组 一.数组(Array)介绍 1.1 基本介绍 1.2 数组的特点 二.数组的声明与初始化 2.1 数组声明 2.2 常见的数据类型声明方法 2.3 数 ...