当前位置: 首页 > news >正文

react中的useState和Hook、副作用

react的组件分为类组件和函数组件,Hook 是一种特殊的函数,可以让你在函数组件中使用类组件中才有的一些特性。useState、useEffect、useReducer都是Hook。其中useState用于在函数组件中添加状态,useEffect用于在函数组件中执行副作用,而useReducer则是useState的加强版。在 React 中,“副作用”(side effect)通常指的是那些在组件渲染之外发生的操作,即那些不直接参与 UI 渲染的行为。这些副作用可以包括数据获取、订阅服务、记录日志、修改 DOM、设置定时器等任何与组件渲染本身无关的操作。

一、useState

react、vue这类框架,我看都属于单页面应用(SPA)。也就是,所有的内容呈现,都在一张页面中完成。我们所看到的其中千变万化,内有乾坤,都是javascript控制的结果。javascript改变页面中变量或元素的值,页面需要重新渲染才能反映最新结果。那么如何才能让页面重新渲染反映最新结果呢,在vue中,大概就是要将变量声明为所谓响应式,比如

const state = reactive({v1:0,v2:false
})

而在react中,就稍有点复杂。react也是组件式开发,但它的组件分为类组件和函数组件。类组件出现时间较早,较为笨重,函数组件是后来才有的,相对较为轻盈,且越来越流行。当然,类组件也不可或缺,各自有适用场景。比如当需要用到生命周期事件时,就要使用类组件。比如组件加载完毕就怎样怎样,组件卸载又如何如何,诸如此类。

react中,如果是类组件,使用 this.state 来定义组件的状态,使用 this.setState() 方法来更新状态。如果是函数组件则使用useState来设置状态。

1、类组件中控制状态

import React, { Component } from 'react';class Counter extends Component {constructor(props) {super(props);this.state = {count: 0};this.handleIncrement = this.handleIncrement.bind(this);this.handleReset = this.handleReset.bind(this);}handleIncrement() {this.setState(prevState => ({count: prevState.count + 1}));}handleReset() {this.setState({ count: 0 });}render() {return (<div><p>Count: {this.state.count}</p><button onClick={this.handleIncrement}>Increment</button><button onClick={this.handleReset}>Reset</button></div>);}
}export default Counter;

2、函数组件中使用useState控制状态

useState 接受一个参数作为初始状态,并返回一个包含两个元素的数组:

import React, { useState } from 'react';function Example() {// 设置初始状态为 0const [count, setCount] = useState(0);return (<div><p>You clicked {count} times</p><button onClick={() => setCount(count + 1)}>Click me</button></div>);
}

二、useReducer

useReducer是useState的威力加强版(也就是说,它也只用在函数组件中)。useReducer 通常用于替代 useState,当状态逻辑变得更加复杂时,使用 useReducer 可以让代码更易于理解和维护。

useReducer 接受一个 reducer 函数和一个初始状态作为参数,并返回一个包含当前状态和一个 dispatch 函数的数组。其中reducer函数是自定义的,主要是根据参数来设置各个状态值。也就是说,useState设置一个状态值,而useReducer可以设置多个状态值。而dispatch函数则负责执行reducer函数。(真绕啊)

import React, { useReducer } from 'react';function counterReducer(state, action) {switch (action.type) {case 'increment':return { count: state.count + 1 };case 'decrement':return { count: state.count - 1 };case 'reset':return { count: 0 };default:throw new Error();}
}function Counter() {const [state, dispatch] = useReducer(counterReducer, { count: 0 });return (<div><p>Count: {state.count}</p><button onClick={() => dispatch({ type: 'increment' })}>Increment</button><button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button><button onClick={() => dispatch({ type: 'reset' })}>Reset</button></div>);
}export default Counter;

三、useEffect

useEffect用于在函数组件中执行副作用操作。副作用可以包括数据获取、订阅服务、记录日志、直接操作 DOM 等与渲染本身不直接相关的操作。

1、类组件执行副作用操作

类组件可以通过生命周期方法来处理副作用,例如:

componentDidMount 用于在组件挂载后执行副作用。
componentDidUpdate 用于在组件更新后执行副作用。
componentWillUnmount 用于在组件卸载前清理副作用。

2、函数组件中执行副作用操作

函数组件,可以使用 useEffect Hook 来处理副作用。useEffect就是类组件中上述三个生命周期方法(componentDidMount 、componentDidUpdate、componentWillUnmount)的综合体。

useEffect 接受一个回调函数作为第一个参数,该回调函数会在组件渲染之后执行。它还可以接受一个可选的依赖项数组作为第二个参数,该数组定义了哪些变量的变化会导致副作用回调重新运行。

import React, { useState, useEffect } from 'react';function Example() {const [count, setCount] = useState(0);useEffect(() => {document.title = `You clicked ${count} times`;// 清理副作用return () => {document.title = 'React App';};}, [count]); // 依赖项数组,只在 count 改变时运行return (<div><p>You clicked {count} times</p><button onClick={() => setCount(count + 1)}>Click me</button></div>);
}

当 useEffect 的依赖项数组为空时,这意味着副作用回调函数仅会在组件挂载完成后运行一次,并且在组件卸载前运行清理函数(如果有的话)。这是因为空数组 [] 表示没有任何依赖项,所以副作用回调不会因为任何状态或属性的变化而重新运行。

import React, { useEffect } from 'react';function Example() {useEffect(() => {console.log('Component mounted');// 设置一个定时器const timer = setInterval(() => {console.log('Timer tick');}, 1000);// 清理副作用return () => {console.log('Component will unmount');clearInterval(timer); // 清除定时器};}, []); // 依赖项为空数组return (<div><p>Hello, World!</p></div>);
}

四、Hook

1、Hook专属于类组件

在 React 中,Hooks 是一种允许在函数组件中使用状态和其他 React 特性的机制。Hooks 使得函数组件能够具有与类组件相同的功能,同时保持代码的简洁性和可读性。

2、Hooks 的规则

为了确保 Hooks 正确工作,需要遵循以下规则:

只在顶层调用 Hooks:不要在循环、条件或嵌套函数内部调用 Hooks。
只在 React 函数中调用 Hooks:不要在普通的 JavaScript 函数中调用 Hooks。

通过遵循这些规则,可以确保 Hooks 在每次渲染时都按照预期工作,并且状态管理逻辑是可预测的。

3、常用Hooks

一些常用的 Hooks:

useState
用于在函数组件中添加状态。它接受一个初始值,并返回一个状态值和一个更新该状态的方法。

useEffect
用于执行副作用操作,如数据获取、订阅或手动更改 DOM。它类似于类组件中的 componentDidMount、componentDidUpdate 和 componentWillUnmount。

useContext
用于消费 React Context 对象中的值。这比使用 Consumer 组件或 withContext 高阶组件更简洁。

useReducer
类似于 useState,但它允许你使用 Reducer 模式管理状态,这对于复杂的组件状态非常有用。

useCallback
用于返回一个被优化过的函数引用,以避免在每次渲染时创建新的函数。

useMemo
用于缓存昂贵的计算结果,以避免在每次渲染时重新计算。

useRef
创建一个可变的引用对象。它的 .current 属性被初始化为传递的参数(initialValue)。返回的对象将在组件的整个生命周期内保持不变。

useImperativeHandle
自定义暴露给父组件的 ref 的值。

useLayoutEffect
类似于 useEffect,但在所有 DOM 更新完成后同步运行。这使得它适合于布局相关的操作。

五、副作用

在 React 中,术语“副作用”(side effect)用来描述那些不在组件渲染过程中直接发生的操作。换句话说,副作用是指那些在组件的生命周期中执行的、与 UI 渲染逻辑无关的操作。这些操作可能会对应用程序的状态、DOM 或外部系统产生影响。

1、为什么称为“副作用”

副作用这个词来源于函数式编程的概念,在函数式编程中,一个纯粹的函数只依赖于它的输入参数,并且只产生输出而不修改任何外部状态。在这样的环境中,函数不应该有除了返回值之外的任何其他效果。然而,在实际的编程中,特别是在 React 这样的框架中,我们经常需要执行一些非纯粹的操作,比如数据获取、DOM 操作、设置定时器等。这些操作虽然不是纯粹的,但对于应用程序的正常运行是必不可少的。

在 React 中,常见的副作用包括但不限于:

1)数据获取:
从服务器或其他数据源获取数据。
通常在组件加载时或状态/属性发生变化时执行。

2)订阅服务:
订阅 WebSocket、RSS Feed 或其他实时数据流。
在组件卸载时取消订阅以避免内存泄漏。

3)设置定时器:
使用 setTimeout 或 setInterval 来执行延迟或周期性的任务。
在组件卸载时清除定时器以避免内存泄漏。

4)记录日志:
记录用户交互或调试信息。
不直接影响 UI 的渲染过程。

5)直接操作 DOM:
修改页面上的元素,而不是通过 React 的虚拟 DOM。
这种做法一般不推荐,但在某些情况下可能是必需的。

2、为什么需要处理副作用

处理副作用很重要,因为它们有助于组件与外部世界交互,例如从服务器获取数据或更新外部服务的状态。此外,适当的清理副作用也很重要,以避免内存泄漏或不必要的资源消耗。

相关文章:

react中的useState和Hook、副作用

react的组件分为类组件和函数组件&#xff0c;Hook 是一种特殊的函数&#xff0c;可以让你在函数组件中使用类组件中才有的一些特性。useState、useEffect、useReducer都是Hook。其中useState用于在函数组件中添加状态&#xff0c;useEffect用于在函数组件中执行副作用&#xf…...

Linux嵌入式学习——数据结构——线性表的链式结构

线性表的链式存储 解决顺序存储的缺点&#xff0c;插入和删除&#xff0c;动态存储问题。 特点&#xff1a; 线性表链式存储结构的特点是一组任意的存储单位存储线性表的数据元素&#xff0c;存储单元可以是连续的&#xff0c;也可以不连续。可以被存储在任意内存未被占…...

文本编辑 文本中的各种空格

参考资料 欧文の半角スペースは&#xff12;種類ある!?无中断空格常见空格一览浅析什么是零宽度字符以及零宽度字符在实际中的应用场景空格象形字间隔无中断空格零宽间隔 目录 零. 各种空格在Notepad中的效果一. 半角空格二. 全角空格三. TAB空格四. 无中断空格4.1 定义4.2 H…...

Vue插槽 (Slots)详解

目录 前言基础插槽具名插槽作用域插槽默认插槽动态插槽名总结相关阅读 前言 Vue的插槽&#xff08;Slots&#xff09;是一个非常强大的特性&#xff0c;它允许你在组件的模板中嵌入父组件的内容。插槽使得组件之间的内容分发变得灵活&#xff0c;尤其在构建可复用组件时非常…...

Unity中有关Animation的一点笔记

也许更好的阅读体验 Animation Unity中Animation类并不是直接记载了和播放动画有关的信息&#xff0c;可以简单理解Animation为一个动画播放器&#xff0c;播放的具体内容就像卡带一样&#xff0c;当我们有了卡带后我们可以播放动画。 对应的则是编辑器中的组件 所以Anima…...

module federation模块联邦与微前端

module federation是什么 webpack5新增了module federation&#xff0c;module federation的作用&#xff0c;将每个构建(build)作为容器(这是一个概念)&#xff0c;构建后的资源可以正常部署&#xff0c;同时还具备在运行时对外暴露其中的模块&#xff0c;这就意味着多个构建…...

日常开发记录分享——C#控件ToolTip实现分栏显示内容

文章目录 需求来源实现思路实施请看VCR等等别走&#xff0c;有优化 需求来源 需要在鼠标浮动到指定位置后提示出详细的信息&#xff0c;一开始使用的tooltip实现&#xff0c;但是里面的内容效果并不理想&#xff0c;需要有条理性&#xff0c;于是就想到能不能将展示的东西分列…...

Kettle下载安装

环境说明 虚拟机&#xff1a;Win7&#xff1b;MySql8.0 主机&#xff1a;Win11&#xff1b;JDK1.8&#xff1b;Kettle 9.4&#xff08;Pentaho Data Integration 9.4&#xff09;&#xff08;下载方式见文末&#xff09; 安装说明 【1】解压后运行Spoon.bat 【2】将jar包 复…...

最新版Golang pprof使用(引入、抓取、分析,图文结合)

最新版Golang pprof使用 &#x1f525;具体实践: Go调试神器pprof使用教程Golang线上内存爆掉问题排查&#xff08;pprof&#xff09; Github地址:https://github.com/ziyifast/ziyifast-code_instruction/tree/main/go-demo/go-pprof 引入pprof:import _ “net/http/pprof” …...

vue3学习记录1:emit的写法

emit是用于child组件向parent组件通信的工具&#xff0c;因为vue3的script可以设置为setup&#xff0c;写法同vue2有较大区别。 一、script setup - 直接写 <script lang"ts" setup>const emit defineEmits([close]);function handleClose() {emit(close);}…...

Visual Studio Code + vue快速安装配置Node.js+Vue+webpack+vscode

第一部分&#xff1a;Node.js 第一步&#xff1a;下载Node.js 方法1&#xff1a;链接 下载 | Node.js 中文网 (nodejs.cn) 方法2&#xff1a;百度网盘 链接&#xff1a;https://pan.baidu.com/s/1zIqu8H9rb_I1i-1OWD7swQ?pwdaurk 提取码&#xff1a;aurk --来自百度网盘…...

【Dart 教程系列第 49 篇】什么是策略设计模式?如何在 Dart 中使用策略设计模式

这是【Dart 教程系列第 49 篇】&#xff0c;如果觉得有用的话&#xff0c;欢迎关注专栏。 博文当前所用 Flutter SDK&#xff1a;3.22.1、Dart SDK&#xff1a;3.4.1 文章目录 一&#xff1a;什么是策略设计模式&#xff1f;二&#xff1a;为什么要使用策略设计模式&#xff1…...

BGP路由反射器

原理概述 缺省情况下&#xff0c;路由器从它的一个 IBGP对等体那里接收到的路由条目不会被该路由器再传递给其他IBGP对等体&#xff0c;这个原则称为BGP水平分割原则&#xff0c;该原则的根本作用是防止 AS内部的BGP路由环路。因此&#xff0c;在AS内部&#xff0c;一般需要每台…...

DolphinDB Web 端权限管理:可视化操作指南

在现代数据库管理中&#xff0c;高效和直观的权限管理对于用户的数据安全是至关重要的。过去 DolphinDB 用户需要依赖系统脚本来管理用户和权限&#xff0c;这对于缺乏技术背景的管理员来说既复杂又容易出错。 为了提升用户体验和操作效率&#xff0c;DolphinDB 目前在 Web 上…...

学习Vue2收藏这一篇就够了(如何创建Vue实例)

什么是Vue&#xff1f; Vue是什么&#xff1a;是一个用于构建用户界面的渐进式框架 什么是构建用户界面&#xff1a;基于数据动态渲染页面 什么是渐进式&#xff1a;循序渐进的学习 什么是框架&#xff1a;一整套完整的项目解决方案 创建Vue实例 核心步骤&#xff08;4步…...

Mysql数据库第四次作业

mysql> create table student(sno int primary key auto_increment,sname varchar(30) not null unique,Ssex varchar(2) check (Ssex男 or Ssex女) not null,Sage int not null,Sdept varchar(10) default计算机 not null); mysql> create table Course(Con int primar…...

使用Docker搭建MySql的主从同步+ShardingSphere搭建Mysql的读写分离

参考课程 尚硅谷ShardingSphere5实战教程&#xff08;快速入门掌握核心&#xff09;_哔哩哔哩_bilibili 主服务器 创建容器 docker run -d \ -p 3306:3306 \ -v /kira/mysql/master/conf:/etc/mysql/conf.d \ -v /kira/mysql/master/data:/var/lib/mysql \ -e MYSQL_ROOT…...

数据结构:数据类型与抽象数据类型

数据类型与抽象数据类型 数据类型基本数据类型构造数据类型指针类型枚举类型 抽象数据类型&#xff08;ADT&#xff09;抽象数据类型的组成部分常见的抽象数据类型示例 数据类型与抽象数据类型的区别实现抽象数据类型的具体方式用数组实现栈用链表实现栈 总结 数据类型 数据类…...

西方逻辑史简介

西方逻辑史研究&#xff0c;对形式逻辑实现现代化&#xff0c;对加强西方哲学史研究&#xff0c;对开展科学方法论的研究都有重要意义。西方逻辑史一般被划分成古代、中世纪、现代三个历史时期。本文拟对这三个时期中的七个重要逻辑学家和逻辑学派&#xff1a;亚里士多德、斯多…...

【论文10】复现代码tips

一、准备工作 1.创建一个虚拟环境 conda create --name drgcnn38 python=3.8.18 2.激活虚拟环境 conda activate drgcnn38 注意事项 在Pycharm中终端(terminal)显示PS而不是虚拟环境base 问题如下所示 解决方法:shell路径改成cmd.exe 重启终端显示虚拟环境 3.安装torch …...

生成xcframework

打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式&#xff0c;可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

反向工程与模型迁移:打造未来商品详情API的可持续创新体系

在电商行业蓬勃发展的当下&#xff0c;商品详情API作为连接电商平台与开发者、商家及用户的关键纽带&#xff0c;其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息&#xff08;如名称、价格、库存等&#xff09;的获取与展示&#xff0c;已难以满足市场对个性化、智能…...

【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验

系列回顾&#xff1a; 在上一篇中&#xff0c;我们成功地为应用集成了数据库&#xff0c;并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了&#xff01;但是&#xff0c;如果你仔细审视那些 API&#xff0c;会发现它们还很“粗糙”&#xff1a;有…...

SpringCloudGateway 自定义局部过滤器

场景&#xff1a; 将所有请求转化为同一路径请求&#xff08;方便穿网配置&#xff09;在请求头内标识原来路径&#xff0c;然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

分布式增量爬虫实现方案

之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面&#xff0c;避免重复抓取&#xff0c;以节省资源和时间。 在分布式环境下&#xff0c;增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路&#xff1a;将增量判…...

佰力博科技与您探讨热释电测量的几种方法

热释电的测量主要涉及热释电系数的测定&#xff0c;这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中&#xff0c;积分电荷法最为常用&#xff0c;其原理是通过测量在电容器上积累的热释电电荷&#xff0c;从而确定热释电系数…...

浪潮交换机配置track检测实现高速公路收费网络主备切换NQA

浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求&#xff0c;本次涉及的主要是收费汇聚交换机的配置&#xff0c;浪潮网络设备在高速项目很少&#xff0c;通…...

基于Springboot+Vue的办公管理系统

角色&#xff1a; 管理员、员工 技术&#xff1a; 后端: SpringBoot, Vue2, MySQL, Mybatis-Plus 前端: Vue2, Element-UI, Axios, Echarts, Vue-Router 核心功能&#xff1a; 该办公管理系统是一个综合性的企业内部管理平台&#xff0c;旨在提升企业运营效率和员工管理水…...

群晖NAS如何在虚拟机创建飞牛NAS

套件中心下载安装Virtual Machine Manager 创建虚拟机 配置虚拟机 飞牛官网下载 https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-0.9.2-863.iso 群晖NAS如何在虚拟机创建飞牛NAS - 个人信息分享...

从面试角度回答Android中ContentProvider启动原理

Android中ContentProvider原理的面试角度解析&#xff0c;分为​​已启动​​和​​未启动​​两种场景&#xff1a; 一、ContentProvider已启动的情况 1. ​​核心流程​​ ​​触发条件​​&#xff1a;当其他组件&#xff08;如Activity、Service&#xff09;通过ContentR…...