React 18中hook函数详解之useState和useEffect

前言

React创建组件的方式有三种,分别是函数式组件、类组件,还有createElement组件。react v16.8版本之前函数式组件是没有状态的。但是,自16.8以后得版本有个hook函数,函数式组件也有了状态,反而类组件没有多少人写了,原因在于生命周期很麻烦,也难记。笔者近几年写React项目已经很少使用类组件了。接下来,详细探讨下hook函数,为什么会有那么神奇的效果?

一 、常用的Hook有哪些?

React Hooks 是 React v16.8 之后推出的函数式组件状态管理方案。它是为了解决状态复用、类组件写法麻烦等原因而提出的,Hook函数本质是闭包。Hooks 主要是利用闭包来保存状态,使用链表保存一系列 Hooks,将链表中的第一个 Hook 与 Fiber 关联。在 Fiber 树更新时,就能从 Hooks 中计算出最终输出的状态和执行相关的副作用。Hook函数带来便利有逻辑复用、业务代码更聚合、写法更简洁。

常用的Hook函数useState、useEffect、useRef、useCallback、useMemo、useReducer、useLayoutEffect

二、useState详解

useState是React自带的一个Hook函数,使用useState可声明内部状态变量。useState接收的参数为状态初始值或状态初始化方法,它返回一个数组。数组的第一项是当前状态值,每次渲染其状态值可能都会不同;第二项是可改变对应状态值的set函数,在useState初始化后该函数不会变化。

useState的类型为:

function useState<S>(initialState:S|(() => S )): [S,Dispatch <SetStateAction <S>>];

initialState仅在组件初始化时生效,后续的渲染将忽略initialState:

const [value, setValue] = useState("");
const [count, setCount] = useState(value);

如上例中的value,当初始值传入另一个状态并初始化后,另一个状态函数将不再依赖value的值。

在 class 中,我们需要调用 this.setState() 来更新 count 值,在函数式组件中,我们已经有了 setCount 和 count 变量,所以我们不需要 this:

import {useState} from "react";
const Example = () => {const [count, setCount] = useState(0);return (<div><button onClick={() => {setCount(count+1)}}>点击更新count:{count}     </button></div>)
}

类似于setState,单击按钮时调用setCount更新了状态值count。当调用setCount后,组件会重新渲染,count的值会得到更新。

当传入初始状态为函数时,其仅执行一次,类似于类组件中的构造函数:

useState返回的更新函数也可使用函数式更新:

setCount(preCount => preCount + 1)

如果新的state需要依赖先前的 state 计算得出,那么可以将回调函数当作参数传递给setState。该回调函数将接收先前的state,并将返回的值作为新的state进行更新。

在组件生命周期或React合成事件中,setState是异步;在setTimeout或者原生dom事件中,setState是同步。

为什么react大部分情况setState是异步的呢?假如所有setState是同步的,意味着每执行一次setState时(有可能一个同步代码中,多次setState),都重新vnode diff + dom修改,这对性能来说是极为不好的。如果是异步,则可以把一个同步代码中的多个setState合并成一次组件更新。

三、useEffect详解

useEffect函数会在组件渲染完毕后,执行和渲染无关的副作用,如数据获取,设置订阅以及手动更改 React 组件中的 DOM 等。

有了useEffect,我们可以在函数组件中实现 像类组件中的生命周期那样某个阶段做某件事情,具有:

  • componentDidMount
  • componentDidUpdate
  • componentWillUnmount

基本用法:

useEffect(() => {console.log('这是一个不含依赖数组的useEffect,每次render都会执行!')
})

useEffect接受一个回调函数和一个可选的依赖项数组。回调函数会在组件挂载、更新和卸载时执行,根据依赖项的不同情况选择执行。如果依赖项为空数组,那么回调函数只会在组件挂载和卸载时执行一次。如果依赖项中包含某个状态或属性,那么只有在这个状态或属性发生变化时才会执行回调函数。 

useEffect的规则

  • 没有传第二个参数时,在每次 render 之后都会执行 useEffect中的内容
  • useEffect接受第二个参数来控制跳过执行,下次 render 后如果指定的值没有变化就不会执行
  • useEffect 是在 render 之后浏览器已经渲染结束才执行
  • useEffect 的第二个参数是可选的,类型是一个数组
  • 根据第二个参数的不同情况,useEffect具有不同作用

下面是useEffect的一些常见用法:

1、获取数据和执行网络请求:

import React, { useState, useEffect } from 'react';
import axios from 'axios';function MyComponent() {const [data, setData] = useState([]);useEffect(() => {const fetchData = async () => {const result = await axios.get('/api/data');setData(result.data);}fetchData();}, []);return (<div>{data.map((item) => <div key={item.id}>{item.name}</div>)}</div>);
}export default MyComponent;

2、订阅事件:

import { useEffect } from 'react';function MyComponent() {useEffect(() => {const subscription = myEventEmitter.subscribe('event', () => {// 处理事件逻辑});return () => {subscription.unsubscribe();};}, []);return <div>My Component</div>;
}

3、执行清理操作:

import { useEffect, useState } from 'react';function MyComponent() {const [timer, setTimer] = useState(null);useEffect(() => {const id = setInterval(() => {// 处理定时器逻辑}, 1000);setTimer(id);return () => {clearInterval(timer);};}, []);return <div>My Component</div>;
}

4、使用第三方库:

import { useEffect } from 'react';
import moment from 'moment';function MyComponent() {useEffect(() => {moment.locale('zh-cn');}, []);return <div>{moment().format('LLLL')}</div>;
}

需要注意的是,useEffect回调函数中的操作可能会对应用程序的性能产生影响。如果回调函数执行的操作很耗费资源,那么可能会导致应用程序变慢。因此,需要谨慎使用useEffect,并在需要时进行性能优化。

在使用React Hooks时,需要遵守以下准则及特性要求。

  • 只在顶层使用Hooks。不要在循环、条件或嵌套函数中调用Hooks,确保总是在React函数组件的顶层调用它们。

  • 不要在普通的JavaScript函数中调用Hooks。仅在React的函数组件中调用Hooks,以及在自定义Hook中调用其他Hooks。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/772839.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MyBatis-Plus分页接口实现教程:Spring Boot中如何编写分页查询

&#x1f31f; 前言 欢迎来到我的技术小宇宙&#xff01;&#x1f30c; 这里不仅是我记录技术点滴的后花园&#xff0c;也是我分享学习心得和项目经验的乐园。&#x1f4da; 无论你是技术小白还是资深大牛&#xff0c;这里总有一些内容能触动你的好奇心。&#x1f50d; &#x…

Unity VisionOS开发流程

Unity开发环境 Unity Pro, Unity Enterprise and Unity Industry 国际版 Mac Unity Editor(Apple silicon) visionOS Build Support (experimental) 实验版 Unity 2022.3.11f1 NOTE: 国际版与国服版Pro账通用&#xff0c;需要激活Pro的许可证。官方模板v0.6.2,非Pro版本会打…

稀碎从零算法笔记Day29-LeetCode:单词拆分

死磕dp的第二天了 题型&#xff1a;dp&#xff0c;字符串&#xff0c;二维数组&#xff0c;背包类 链接&#xff1a;139. 单词拆分 - 力扣&#xff08;LeetCode&#xff09; 来源&#xff1a;LeetCode 题目描述 给你一个字符串 s 和一个字符串列表 wordDict 作为字典。如果…

【探究图论中dfs记忆化,搜索,递推,回溯关系】跳棋,奶牛隔间, 小A和uim之大逃离 II

本篇很高能&#xff0c;如有错误欢迎指出&#xff0c;本人能力有限&#xff08;需要前置知识记忆化dfs&#xff0c;树形dp&#xff0c;bfsdp&#xff0c;tarjan&#xff09; 另外&#xff0c;本篇之所以属于图论&#xff0c;也是想让各位明白&#xff0c;dfs就是就是在跑图&am…

mysql80-DBA数据库学习2

权限管理 创建用户 create user user1localhost identified by QianFeng123; select * from mysql.user; 或者select * from mysql.user\G进行分行显示 密码要求&#xff1a; 1组成&#xff1a; 由小写字母、大写字母、数字、字符 中的三项组成 &#xff0c;也就是3/4 2长度…

jupyter notebook指定虚拟环境

要在 Jupyter notebook 中使用特定的虚拟环境&#xff0c;可以按照以下步骤操作&#xff1a; 1、首先&#xff0c;确保已经安装了 Jupyter notebook 和虚拟环境工具&#xff08;比如 virtualenv 或 conda&#xff09;。 2、在命令行中&#xff0c;激活你想要使用的虚拟环境。…

单片机---独立按键

[3-1] 独立按键控制LED亮灭_哔哩哔哩_bilibili 按下的时候连接&#xff0c;松开的时候断开。 一头接GND&#xff08;电源负极&#xff09;&#xff0c;另一头接I/O口。 单片机上电时&#xff0c;所有I/O口为高电平。 按键没有按下&#xff0c;I/O口为高电平。 按键按下&…

标题:深入了解 ES6 模块化技术

在 ES6 版本之前&#xff0c;JavaScript 一直缺乏一个内置的模块系统&#xff0c;这给大型项目的开发带来了一些挑战。ES6 引入了模块化的概念&#xff0c;为 JavaScript 开发者提供了一种更好的组织和管理代码的方式。 模块是 JavaScript 的一种代码组织方式&#xff0c;它将代…

界面控件DevExpress WinForms/WPF v23.2 - 电子表格支持表单控件

DevExpress WinForm拥有180组件和UI库&#xff0c;能为Windows Forms平台创建具有影响力的业务解决方案。DevExpress WinForm能完美构建流畅、美观且易于使用的应用程序&#xff0c;无论是Office风格的界面&#xff0c;还是分析处理大批量的业务数据&#xff0c;它都能轻松胜任…

数据结构奇妙旅程之深入解析插入排序

插入排序&#xff08;Insertion Sort&#xff09;是一种简单直观的排序算法。它的工作原理是通过构建有序序列&#xff0c;对于未排序数据&#xff0c;在已排序序列中从后向前扫描&#xff0c;找到相应位置并插入。插入排序在实现上&#xff0c;通常采用in-place排序&#xff0…

QGraphicsView(平移/缩放/旋转)

简述 Graphics View提供了一个平台&#xff0c;用于大量自定义 2D 图元的管理与交互&#xff0c;框架包括一个事件传播架构&#xff0c;支持场景 Scene 中的图元 Item 进行精确的双精度交互功能。Item 可以处理键盘事件、鼠标按下、移动、释放和双击事件&#xff0c;同时也能跟…

鸿蒙OS封装【axios 网络请求】(类似Android的Okhttp3)

Okhttp.ets /*** 网络请求*/ import axios from ohos/axios import httpConstants from ../net/HttpConstants import errorCode from ../utils/errorCode import toast from ../utils/ToastUtils import router from ../utils/RouterUtils import SPUtils from ../utils/SPUt…

毕马威:量子计算成未来3-5年重大挑战

毕马威&#xff08;KPMG&#xff09;是一家全球性的专业服务网络&#xff0c;其历史可追溯到19世纪末。作为“四大”会计师事务所之一&#xff0c;毕马威在审计、税务和咨询服务领域享有盛誉。公司在全球范围内拥有多个办事处&#xff0c;服务遍及各个行业&#xff0c;包括金融…

5.1 物联网RK3399项目开发实录-Android开发之ADB使用(wulianjishu666)

物联网项目开发实例&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/11VQMhHfIL9mZhNlls4wmjw?pwd0gfa 1. ADB 使用 1.1. 前言 ADB&#xff0c;全称 Android Debug Bridge&#xff0c;是 Android 的命令行调试工具&#xff0c;可以完成多种功能&#xff0c;如跟踪系…

CentOS Stream 8系统配置阿里云YUM源

Linux运维工具-ywtool 目录 一.系统环境二.修改yum文件2.1 CentOS-Stream-AppStream.repo2.2 CentOS-Stream-BaseOS.repo2.3 CentOS-Stream-Extras.repo 三.只有一个配置文件四.其他知识4.1 如果想要启用其他源,修改文件配置:enabled14.2 国内源链接 一.系统环境 CentOS Strea…

Linux一键式安装JDK、Mysql、Redis、Nginx(附带安装包,无需手动配置密码等)

安装包 新服务器安装前置准备 1. 设置系统时区 # 查看服务器时区 timedatectl # 设置服务器时区为上海 timedatectl set-timezone Asia/Shanghai # 设置系统时间为“2021-3-19 11:00:00” date -s "2021-3-19 11:00:00" # 查看校准后的系统时间 date …

[C++]内联函数(内联函数的概念,内联函数的特性,内联函数与宏的区别)

一、内联函数的概念 以inline修饰的的函数叫内联函数&#xff0c;编译时C编译器会在调用内联函数的位置将内联函数展开&#xff0c;内联函数没有调用函数参数压栈的开销&#xff0c;内联函数可以提高程序的运行效率。 例子&#xff1a; 没有使用内联函数 使用内联函数&#xff…

uniapp小程序中onShareAppMessage(OBJECT)实现带参数的分享功能

一、引言 小程序中用户点击分享后&#xff0c;在 js 中定义 onShareAppMessage 处理函数&#xff08;和 onLoad 等生命周期函数同级&#xff09;&#xff0c;设置该页面的分享信息。 用户点击分享按钮的时候会调用。这个分享按钮可能是小程序右上角原生菜单自带的分享按钮&…

【SpringBoot整合系列】SpringBoot3.x整合Swagger

目录 产生背景官方解释&#xff1a;作用SpringBoot3整合Swagger注意事项swagger3 常用注解SpringBoot3.x整合Swagger1.创建工程(jdk:17,boot:3.2.4)2.引入pom依赖3.application.yml添加配置4.添加swagger3.0配置5.控制器层(Controller)6.模型层(Model)7.启动并测试【Get请求接口…

一、Spring Cloud(Base工程构建)

一、Spring Cloud&#xff08;Base工程构建&#xff09; 1.1 Spring Cloud 简述 1.1.1 Spring Cloud 版本推荐 在讲解 Spring Cloud 之前&#xff0c;首先推荐一下各个依赖的版本&#xff0c;以免出现版本错误 版本推荐 必须根据以上版本&#xff0c;否则可能会出现一些不…