React Hooks小记(一)_useState

useState

1. 基本用法

useState,能让函数组件拥有自己的状态,因此,它是一个管理状态的 hooks API。通过 useState 可以实现状态的初始化、读取、更新。

基本语法格式如下:

const [状态名, set函数] = useState(初始值)

其中:状态名所代表的数据,可以被函数组件使用;如果要修改状态名所代表的数据,需要调用 set 函数 进行修改。例如:

import { useState } from 'react' 
export function Count() { // 定义状态 count,其初始值为 0 // 如果要修改 count 的值,需要调用 setCount(新值) 函数 const [count, setCount] = useState(0) return ( <> <!-- 在函数组件内,使用名为 count 的状态 --> <h1>当前的 count 值为:{count}</h1> <!-- 点击按钮时,调用 setCount() 函数,为 count 赋新值 --> <button onClick={() => setCount(count + 1)}>点我+1</button> </> ) 
}

2. 状态变化时,会触发函数组件的重新执行

在函数组件中使用 setState 定义状态之后,每当状态发生变化,都会触发函数组件的重新执行,从而根据最新的数据更新渲染 DOM 结构。

例如:

import { useState } from 'react' 
export function Count() { // 定义状态 count,其初始值为 0 // 如果要修改 count 的值,需要调用 setCount(新值) 函数 const [count, setCount] = useState(0) // 每次 count 值发生变化,都会打印下面的这句话: console.log('组件被重新渲染了') const add = () => { setCount(count + 1) } return ( <> <!-- 在函数组件内,使用名为 count 的状态 --> <h1>当前的 count 值为:{count}</h1> <!-- 点击按钮时,在 add 处理函数中,调用 setCount() 函数,为 count 赋新值 --> <button onClick={add}>+1</button> </> ) 
}

注意:当函数式组件被重新执行时,不会重复调用 useState() 给数据赋初值,而是会复用上次的 state 值。

3. 以【函数】形式为状态赋初始值

在使用 useState 定义状态时,除了可以直接给定初始值,还可以通过函数返回值的形式,为状态赋初始值,语法格式如下:

const [value, setValue] = useState(() => 初始值)

例如:

export const DateCom: React.FC = () => { // const [date] = useState({ year: 2023, month: 9, day: 11 }) const [date, setDate] = useState(() => { const dt = new Date() return { year: dt.getFullYear(), month: dt.getMonth() + 1, day: dt.getDate() } }) return ( <> <h1>今日信息:</h1> <p>年份:{date.year}</p> <p>月份:{date.month}</p> <p>日期:{date.day}</p> </> ) 
}

注意:以函数的形式为状态赋初始值时,只有组件首次被渲染才会执行 fn 函数;当组件被更新时,会以更新前的值作为状态的初始值,赋初始值的函数不会执行。

4. useState 是异步变更状态的

调用 useState() 会返回一个变更状态的函数,这个函数内部是以异步的形式修改状态的,所以修改状态后无法立即拿到最新的状态,例如:

export const Count: React.FC = () => { const [count, setCount] = useState(() => 0) const add = () => { // 1. 让数值自增+1 setCount(count + 1) // 2. 打印 count 的值 console.log(count) } return ( <> <h1>当前的 count 值为:{count}</h1> <button onClick={add}>+1</button> </> ) 
}

在上述代码的第8行,打印出来的 count 值是更新前的旧值,而非更新后的新值。证明 useState 是异步变更状态的。

5. 结合 useEffect 监听状态的变化

为了能够监听到状态的变化,react 提供了 useEffect 函数。它能够监听依赖项状态的变化,并执行对应的回调函数。基本语法格式如下:

useEffect(() => { /* 依赖项变化时,要触发的回调函数 */ }, [依赖项])

例如:

export const Count: React.FC = () => { const [count, setCount] = useState(() => 0) const add = () => { setCount(count + 1) } // 当 count 变化后,会触发 useEffect 指定的回调函数 useEffect(() => { console.log(count) }, [count]) return ( <> <h1>当前的 count 值为:{count}</h1> <button onClick={add}>+1</button> </> ) 
}

注意:useEffect 也是 React 提供的 Hooks API,后面的课程中会对它进行详细的介绍。

6. 注意事项

6.1 更新对象/数组类型的值

知识回顾:判断对象的值是否改变,看的是地址是否改变

如果要更新对象类型的值,并触发组件的重新渲染,则必须使用展开运算符Object.assign() 生成一个新对象,用新对象覆盖旧对象,才能正常触发组件的重新渲染。

示例代码如下:

export const UserInfo: React.FC = () => { const [user, setUser] = useState({ name: 'zs', age: 12, gender: '男' }) const updateUserInfo = () => { user.name = 'Jesse Pinkman' // 下面的写法是错误的,因为 set 函数内部,会对更新前后的值进行对比; // 由于更新前后的 user,原值的引用和新值的引用相同, // 所以 react 认为值没有发生变化,不会触发组件的重新渲染。 // setUser(user) // 【解决方案】:用新对象的引用替换旧对象的引用,即可正常触发组件的重新渲染。 // 1、setUser({ ...user }) // 2、setUser(Object.assign({}, user)) // 通常在实际开发中,经常结合【展开运算符 + 属性值覆盖】的形式更新对象的属性值: setUser({...user, name: 'Jesse Pinkman'}) } return ( <> <h1>用户信息:</h1> <p>姓名:{user.name}</p> <p>年龄:{user.age}</p> <p>性别:{user.gender}</p> <button onClick={updateUserInfo}>更新用户信息</button> </> ) 
}

6.2 解决值更新不及时的 Bug

当连续多次以相同的操作更新状态值时,React 内部会对传递过来的新值进行比较,如果值相同,则会屏蔽后续的更新行为,从而防止组件频繁渲染的问题。这虽然提高了性能,但也带来了一个使用误区,例如:

export const Count: React.FC = () => { const [count, setCount] = useState(() => 0) const add = () => { // 1. 希望让 count 值从 0 自增到 1 setCount(count + 1) // 2. 希望让 count 值从 1 自增到 2 setCount(count + 1) } return ( <> <h1>当前的 count 值为:{count}</h1> <button onClick={add}>+1</button> </> ) 
}

经过测试,我们发现上述代码执行的结果,只是让 count 从 0 变成了 1,最终的 count 值并不是 2。Why?

因为 setCount 是异步地更新状态值的,所以前后两次调用 setCount 传递进去的新值都是 1 。React 内部如果遇到两次相同的状态,则会默认阻止组件再次更新。

为了解决上述的问题,我们可以使用函数的方式给状态赋新值。当函数执行时才通过函数的形参,拿到当前的状态值,并基于它返回新的状态值。

示例代码如下:

export const Count: React.FC = () => { const [count, setCount] = useState(() => 0) const add = () => { // 传递了更新状态的函数进去 setCount((c) => c + 1) setCount((c) => c + 1) } return ( <> <h1>当前的 count 值为:{count}</h1> <button onClick={add}>+1</button> </> ) 
}

【总结】setState 更新值的两种方式

​ 1、setCount(新值)

​ 2、setCount((pre) => 基于pre计算并返回的新值)

tips:当我们修改 state 时,如果新值依赖旧值,应选择第二种方式更新状态

6.3 使用 setState 模拟组件的强制刷新

在函数组件中,我们可以通过 useState模拟 forceUpdate 的强制刷新操作。因为只要 useState 的状态发生了变化,就会触发函数组件的重新渲染,从而达到强制刷新的目的。具体的代码示例如下:

export const FUpdate: React.FC = () => { const [, forceUpdate] = useState({}) // 每次调用 onRefresh 函数,都会给 forceUpdate 传递一个新对象 // 从而触发组件的重新渲染 const onRefresh = () => forceUpdate({}) return ( <> <button onClick={onRefresh}>点击强制刷新 --- {Date.now()}</button> </> ) 
}

注意:因为每次传入的对象的地址不同,所以一定会使组件刷新。

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

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

相关文章

Java学习 - MySQL数据库中提到的 事务 是什么? 怎么使用?

事务是什么 事务是指由一条或者多条SQL语句组成的单元&#xff0c;这个单元在执行过程中具有ACID四个特征 事务的特征(ACID) A&#xff1a;原子性 事务是一个不可再拆分的最小工作单元事务中的SQL要不都成功&#xff0c;要不都失败&#xff08;回滚&#xff09; C&#xf…

JavaScript中有哪几种循环?他们的运用场景在哪?

在JavaScript中&#xff0c;主要有三种循环结构&#xff1a;for循环、while循环和do...while循环。每种循环都有其特定的运用场景。 1.for循环 for循环是最常用的循环结构之一&#xff0c;它通常用于在知道循环次数的情况下执行一段代码。for循环的基本语法如下&#xff1a; …

如何在 Vue 3 中使用 vue3-print-nb 实现灵活的前端打印

你好&#xff0c;我是小白Coding日志&#xff0c;一个热爱技术的程序员。在这里&#xff0c;我分享自己在编程和技术世界中的学习心得和体会。希望我的文章能够给你带来一些灵感和帮助。欢迎来到我的博客&#xff0c;一起在技术的世界里探索前行吧&#xff01; 前言 在前端开…

Vue38-组件的几个注意点

一、组件回顾 1-1、创建组件 1-2、注册组件 1-3、使用组件 二、注意点&#xff1a;组件名 2-1、组件名一个单词&#xff1a;纯小写&#xff0c;或者&#xff0c;首字母大写 2-2、多个单词&#xff1a; 1、xx-bbbb 2、AaaBbbb&#xff1a;每个单词的首字母都大写 前提&…

【NUJ PA2】Read a Makefile

这里是NJU的PA2.2里面要求读懂的Makefile&#xff0c;是abstract-machine的。这里会放一些与读懂这个Makefile有关的知识。 下面是用ChatGPT解释的代码。只做大致的了解&#xff0c;写Makefile的时候还是要具体去看官方手册。 官方手册&#xff1a;make.pdf (gnu.org) # Makef…

军用FPGA软件 Verilog语言的编码准测之复位

军用FPGA软件 Verilog语言的编码准测之复位 语言 &#xff1a;Verilg HDL EDA工具&#xff1a;ISE、Vivado、Quartus II 军用FPGA软件 Verilog语言的编码准测之复位一、引言二、基本编程规范之复位强制准则1----禁止将异步的置位/复位信号连接到非置位/复位端强制准则2----禁止…

Json-server 的使用教程

目录 前言一、简介二、安装与配置1. 安装 node-js2. npm 镜像设置3. 安装 json-server 三、使用1. 创建本地数据源2. 启动 Json Server3. 操作数据&#xff08;1&#xff09;查询数据&#xff08;2&#xff09;新增数据&#xff08;3&#xff09;修改数据&#xff08;4&#xf…

RTOS笔记--资源管理

资源管理 资源管理&#xff0c;其实就是前面介绍过的通知方式中的队列信号量互斥量等是如何访问临界资源的&#xff0c;如何做到完全互斥。 在之前举过一个例子&#xff1a;当我们使用全局变量来进行互斥操作时&#xff0c;有可能在改写全局变量时被切换使得不再互斥&#xff0…

【SpringBoot】深入分析 SpringApplication 源码:彻底理解 SpringBoot 启动流程

在黄昏的余晖里&#xff0c;梦境渐浓&#xff0c;如烟如雾。心随星辰&#xff0c;徜徉远方&#xff0c;岁月静好&#xff0c;愿如此刻般绵长。 文章目录 前言一、SpringBoot 应用二、SpringApplication2.1 SpringApplication 中的属性2.2 SpringApplication 的构造器2.3 Sprin…

185. 部门工资前三高的所有员工

185. 部门工资前三高的所有员工 题目链接&#xff1a;185. 部门工资前三高的所有员工 代码如下&#xff1a; # Write your MySQL query statement below select d.Name as Department,e1.Name as Employee,e1.Salary from Employee as e1 join Department as d on e1.Depart…

【Linux】基础IO——文件描述符,重定向,FILE

话接上篇&#xff1a; 1.文件描述符fd 磁盘文件 VS 内存文件&#xff1f; 当文件存储在磁盘当中时&#xff0c;我们将其称之为磁盘文件&#xff0c;而当磁盘文件被加载到内存当中后&#xff0c;我们将加载到内存当中的文件称之为内存文件。磁盘文件和内存文件之间的关系就像程…

JVM 三色标记算法

三色标记算法核心原理 三色标记算法是一种JVM的垃圾标记算法&#xff0c;CMS/G1垃圾回收器就是使用的这种算法&#xff0c;它可以让JVM在不发生或者尽可能短的发生STW&#xff08;Stop The World&#xff09;的情况下进行垃圾的标记和清除。 顾名思义&#xff0c;三色标记算法…

【名词解释】Unity中的3D物理系统:刚体

Unity中的3D物理系统是用于模拟现实世界中物体的运动和相互作用的一套工具和组件。刚体&#xff08;Rigidbody&#xff09;是Unity 3D物理系统中的一个核心组件&#xff0c;它允许游戏对象&#xff08;GameObject&#xff09;受到重力和外力的影响&#xff0c;并参与碰撞检测。…

实现JWT认证与授权的Spring Boot项目详解

我们将详细介绍如何使用JWT&#xff08;JSON Web Tokens&#xff09;结合Spring Boot框架实现用户认证和授权系统。此方案将包括用户注册、登录以及通过JWT令牌进行后续请求的身份验证过程。我们将从引入必要的依赖开始&#xff0c;然后逐步构建项目的各个部分&#xff0c;包括…

精品丨PowerBI迁移到SSAS

业务场景&#xff1a; 企业初期在进行 BI 可视化路线的时候&#xff0c;往往不会选择方案较为完整的SSAS&#xff0c;而是会选择轻量的 PowerBI 方案&#xff0c;究其根本还是软件成本的问题。 但是随着模型越来越臃肿&#xff0c;维护成本越来越高&#xff0c;有很多模型需要进…

【名词解释】Unity中的3D坐标系

Unity中的3D坐标系是一个基于右手定则的笛卡尔坐标系&#xff0c;它定义了Unity场景中所有3D对象的位置、旋转和缩放。以下是一些基本的名词解释和使用方法&#xff1a; 名词解释&#xff1a; X轴&#xff1a;水平方向&#xff0c;从屏幕左侧向右延伸。Y轴&#xff1a;垂直方…

SQL Auto Increment

SQL Auto Increment 在关系型数据库中&#xff0c;自动增量&#xff08;Auto Increment&#xff09;是一个常见且实用的特性。它允许数据库自动为表中插入的新行分配唯一的标识符&#xff0c;通常用于主键字段。本文将深入探讨SQL中的自动增量功能&#xff0c;包括其工作原理、…

Java面向对象-抽象类和抽象方法

Java面向对象-抽象类和抽象方法 1、代码案例展示2、抽象类和抽象方法的关系&#xff1a; 1、代码案例展示 1、在一个类中会有一类方法&#xff0c;无需重写&#xff0c;直接使用 2、在一个类中会有一类方法&#xff0c;会对这个方法进行重写 3、一个方法的方法体去掉&#xff…

【文心智能体分享】日记周报助手

引言 在繁忙的实习生活中&#xff0c;你是否曾为如何整理日常的工作日志、周报、月报而烦恼&#xff1f;现在&#xff0c;我们为你带来了一个全新的智能体——“日记周报助手”&#xff0c;它将成为你实习过程中的得力助手&#xff0c;帮你轻松整理实习日志&#xff0c;让你的…

mysql 中的锁

一.锁的介绍 锁是计算机协调多个进程或线程并发访问某一资源的机制&#xff0c;在数据库中&#xff0c;除了传统的计算资源&#xff08;cpu&#xff0c;ram&#xff0c;i/o&#xff09;的争用以外&#xff0c;数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性…