react的state和useState你了解多少?带你深入react state useState

news2024/11/24 0:08:52

state和useState是react中很重要的概念,虽然笔者一直在用,但是总感觉有些地方认识不够透彻。于是乎,笔者重新阅读学习了react官方文档,感觉受益匪浅。希望能用尽量通俗简洁的语言把吸收的知识表述清楚,便写下此文。

如有错误,欢迎指正~

目录

state

普通变量

深入了解state

useState

基本用法

set函数触发重新渲染

*state--快照(重要!)

 例一

例二 

例三

例四:更新函数 

例五

总结


state

普通变量

当我们需要数据响应式渲染到页面上时,我们就不能使用普通的变量了:

  1. 普通变量无法在多次渲染中持久保存:当 React 再次渲染这个组件时,它会从头开始渲染——不会考虑之前对局部变量的任何更改。
  2. 更改局部变量不会触发渲染。 React 没有意识到它需要使用新数据再次渲染组件。

此时,我们就需要useState来声明state去解决上面的问题。

深入了解state

官网中说到:“State是隔离私有的”,那么这句话应该如何理解呢?

隔离:State 是屏幕上组件实例内部的状态。换句话说,如果你渲染同一个组件两次,每个副本都会有完全隔离的 state!改变其中一个不会影响另一个。

私有:与 props 不同,state 完全私有于<声明>它的组件。父组件无法更改它。

//隔离:son组件渲染两次,两个son组件中的state互相隔离,互不影响
//私有:parent不知道son组件中的state的任何信息,无法改变son组件的state(符合react的单项数据流动特性)
<parent>
    <son/>
    <son/>
</parent>

useState

基本用法

useState 返回一个由两个值组成的数组:

当前的 state:在首次渲染时,它将与你传递的 initialState 相匹配。
set 函数:它可以让你将 state 更新为不同的值并《触发重新渲染》。

const [state, setState] = useState(initialState);

set函数触发重新渲染

在react中,触发组件渲染有两种情况:

  1. 组件的 初次渲染:调用render函数
  2. 组件(或者其祖先之一)的 状态发生了改变:调用set函数

在使用set函数之后,react会从该state声明(useState)的组件开始,根据更改后的state,重新渲染该组件&所有子组件。

*state--快照(重要!)

为了更好的理解,我们可以把state理解为一张快照:当 React 调用你的组件时,它会为特定的那一次渲染提供一张 state 快照。你的组件会在其 JSX 中返回一张包含一整套新的 props 和事件处理函数的 UI 快照 ,其中所有的值都是 根据那一次渲染中 state 的值 被计算出来的。

为了更好的理解,我们接下来看几个例子

 例一

该例子是一个简易计数器,click事件里面调用了三次setNumber,当我们点击按钮之后会发生什么呢?

//App.js
import { useState } from 'react';

export default function Counter() {
  const [number, setNumber] = useState(0);

  return (
    <>
      <h1>{number}</h1>
      <button onClick={() => {
        setNumber(number + 1);
        setNumber(number + 1);
        setNumber(number + 1);
      }}>+3</button>
    </>
  )
}

点击之后发现,每次点击值只增加1,而非3。这是为什么呢?

我们来捋一下:

step1:该组件第一次渲染时,number的值是0,所以后续的渲染都是根据0这个值进行的计算。

step2:第一次组件渲染完成后,我们看下的onClick函数:

<button onClick={() => {
  setNumber(number + 1);
  setNumber(number + 1);
  setNumber(number + 1);
}}>+3</button>

以下是这个按钮的点击事件处理函数通知 React 要做的事情:

  1. setNumber(number + 1)number 是 0 所以 setNumber(0 + 1)
    • React 准备在下一次渲染时将 number 更改为 1
  2. setNumber(number + 1)number 是0 所以 setNumber(0 + 1)
    • React 准备在下一次渲染时将 number 更改为 1
  3. setNumber(number + 1)number 是0 所以 setNumber(0 + 1)
    • React 准备在下一次渲染时将 number 更改为 1

尽管你调用了三次 setNumber(number + 1),但在 这次渲染的 事件处理函数中 number 会一直是 0,所以你会三次将 state 设置成 1。这就是为什么在你的事件处理函数执行完以后,React 重新渲染的组件中的 number 等于 1 而不是 3

所以我们在第一次渲染之后,onClick函数可以等价为如下代码: 

<button onClick={() => {
  setNumber(0 + 1);
  setNumber(0 + 1);
  setNumber(0 + 1);
}}>+3</button>

例二 

我们把上面的例子改一下,再预测一下会出现什么结果:

 

//App.js
import { useState } from 'react';

export default function Counter() {
  const [number, setNumber] = useState(0);

  return (
    <>
      <h1>{number}</h1>
      <button onClick={() => {
        setNumber(number + 5);
        alert(number);
      }}>+5</button>
    </>
  )
}

点击之后发现:数字从0变成5了,但是弹窗的数依旧是0。

根据我们上面提到的快照理解,上面的onClick代码可以等价为:

<button onClick={() => {
        setNumber(0 + 5);
        alert(0);
      }}>+5</button>

这样是不是就很好理解了。

例三

我们再改一下:如果我们加一个定时器,想让弹窗在组件重新渲染 之后 才触发,又会怎样呢?

//App.js
import { useState } from 'react';

export default function Counter() {
  const [number, setNumber] = useState(0);

  return (
    <>
      <h1>{number}</h1>
      <button onClick={() => {
        setNumber(number + 5);
        setTimeout(() => {
          alert(number);
        }, 3000);
      }}>+5</button>
    </>
  )

结果: 数字从0变成5了,但是三秒之后的弹窗的数依旧是0。

这是为什么呢?我们看react官方如何解释:

一个 state 变量的值永远不会在一次渲染的内部发生变化, 即使其事件处理函数的代码是异步的。”

React 会使 state 的值始终”固定“在一次渲染的各个事件处理函数内部。

state作为快照,它的值在 React 通过调用你的组件“获取 UI 的快照”时就被“固定”了,哪怕是异步代码,它得到的state值也是在调用时被固定的快照的值。

所以对应函数等价于如下代码:

setNumber(0 + 5);
setTimeout(() => {
  alert(0);
}, 3000);

例四:更新函数 

让我们回到例一,如果我们想在onClick里面写三个set函数来实现加3的效果,那该如何改造呢?

这时候就需要用到更新函数了:在set函数中,传入一个根据队列中的前一个 state 计算下一个 state 的 函数。

简单来说,就是把set函数的参数,从之前的一个值/变量,换成一个函数即可。

更改后的代码见下图:

 这样,每点击一次,加的就是3了。

详细更新过程见下图:

例五

我们再升级一下例4的代码,运行结果会怎样呢?

结果:点击按钮后,从0变成了42。 

详细更新过程见下图:

 

总结

  • 调用set函数会请求一次新的渲染
  • 每个渲染(以及其中的函数)始终“看到”的是 React 提供给这个 渲染的 state 快照
  • 过去创建的事件处理函数拥有的是创建它们的那次渲染中的 state 值。
  • React 会等到事件处理函数中的 所有 代码都运行完毕再处理你的 state 更新。
  • 要在一个事件中多次更新某些 state,你可以使用 setNumber(n => n + 1) 更新函数。

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

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

相关文章

二、DDL-3.数据类型

分为3种&#xff1a;数值类型、字符串类型、日期时间类型。 一、数值类型 【案例】 年龄&#xff1a; age TINYINT UNSIGNED——范围&#xff08;0&#xff0c;255&#xff09;够用 分数&#xff1a;score double(4,1)——分数0-100有小数&#xff0c;4—最高位数&#xff0…

学习开闭原则的方法:成为编程高手的秘诀

成为一名优秀的编程高手&#xff0c;掌握开闭原则是至关重要的。开闭原则是软件设计中的核心概念之一&#xff0c;它能够帮助我们构建可扩展、可维护的代码&#xff0c;提升自身的编程水平。在本文中&#xff0c;我们将分享学习开闭原则的方法&#xff0c;揭示成为编程高手的秘…

记android studio打包踩雷

由于包太大考虑离线打包但是折腾一通打包完之后才发现&#xff0c;如果使用了插件市场上面的付费插件 离线打包时走不通的&#xff0c;只能老老实实付费云打包。

数据结构--图的存储 十字链表、邻接多重表

数据结构–图的存储 十字链表、邻接多重表 十字链表存储有向图 空间复杂度&#xff1a;O(|V||E|) 如何找到指定顶点的所有出边&#xff1f;——顺着绿色线路找 如何找到指定顶点的所有入边&#xff1f;——顺着橙色线路找 注意&#xff1a;十字链表只用于存储有向图 \color{re…

杨辉三角 II

给定一个非负索引 rowIndex&#xff0c;返回「杨辉三角」的第 rowIndex 行。 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 示例 1: 输入: rowIndex 3 输出: [1,3,3,1] 示例 2: 输入: rowIndex 0 输出: [1] 示例 3: 输入: rowIndex 1 输出: [1,1]…

redis 相关

redis相关面试题 redis支持哪几种数据形式&#xff1f; String,hash,set,zset,list redis主要消费什么物理资源&#xff1f; 内存&#xff0c;key-value的形式&#xff0c; redis 具有快速和数据持久化的特征&#xff0c;如果不将数据放在内存中&#xff0c;磁盘 I/O 速度为严…

实现视频监控场景下的抽烟目标检测:改进 YOLOv5 的关键方法与代码实现

文章目录 概要技术细节小结 概要 目标检测是计算机视觉领域的重要任务之一&#xff0c;而改进现有的目标检测模型以实现对细微差异目标的准确检测是当前研究的热点。本文将探讨如何通过对 YOLOv5 进行改进&#xff0c;以增强其对细微差异目标的感知能力。我们将介绍一些关键方…

CN期刊《教师博览》是什么级别的刊物?

CN期刊《教师博览》是什么级别的刊物&#xff1f; 《教师博览》创刊于1993年&#xff0c;经国家新闻出版总署批准&#xff0c;江西省教育厅主管的省级G4学术期刊。 《教师博览》 是江西教育厅主管、江西教育期刊社主办的一份面向全国发行的教育杂志&#xff0c;其文摘版创办于…

pdf怎么分成多个文件?教你4招PDF拆分!

有时候&#xff0c;我们可能需要将一个包含多个页面的PDF文件拆分成多个独立的文件。这样做可以方便我们在需要的时候单独查看或处理某些页面&#xff0c;提高工作效率。本文将介绍四种常用的方法来将PDF文件分割成多个文件&#xff0c;包括使用Adobe Acrobat、记灵在线工具、P…

地埋式积水在线监测系统助力城市内涝解决方案

一、方案背景 随着我国城镇化快速发展&#xff0c;城市建设产生的大量地面硬底化&#xff0c;大部分的降雨将形成地表径流&#xff0c;仅有少量雨水渗入地下&#xff0c;导致城市内涝等一系列问题。当前&#xff0c;全国多地发生洪涝&#xff0c;我国南北方全面进入主汛期。与往…

linux文件系统只读导致监听异常

项目经理发来截图&#xff0c;监听无法启动了&#xff0c;截图如下 orcl:/home/oraclehydb> lsnrctl start LSNRCTL for Linux: Version 11.2.0.4.0 - Production on 18-JUL-2023 11:29:54 Copyright (c) 1991, 2013, Oracle. All rights reserved. Starting /u01/app/…

流体力学中动力粘度和运动粘度的定义和区别

流体力学中动力粘度和运动粘度的定义和相互关系 在流体力学中&#xff0c;常遇到动力粘度和运动粘度参数。本文讲解这两个参数的含义和相关关系。 1.动力粘度&#xff08;Dynamic viscosity&#xff09; 1.1 动力粘度定义 动力粘度&#xff08;dynamic viscosity&#xff0…

2023年在线帮助文档的特点和市场趋势变化

2023年在线帮助文档的特点和市场趋势变化将受到多种因素的影响。随着技术的不断进步和用户需求的变化&#xff0c;在线帮助文档将呈现出一些新的特点和趋势。 以下是可能出现的一些特点和市场趋势变化&#xff1a; 多样化的内容形式&#xff1a; 传统的在线帮助文档通常是以…

gitea使用教程从搭建到远程访问通过API构建仓库上传代码

文章目录 安装gitea远程访问安装gitea docker 安装gitea 教程 安装完成后就进入了类似这样的界面,先注册再登录。 登录后进入首页,包括了对gitea服务的设置和仓库的管理。 点击组织下的加号+用于创建仓库 仓库是git最核心的部分,是代码存储和迭代的容器。 创建仓库后进入…

【Spring Boot】Web开发 — Web开发简介

Web开发简介 首先介绍Spring Boot 提供的Web组件spring-boot-starter-web&#xff0c;然后介绍Controller和RestController注解&#xff0c;以及控制数据返回的ResponseBody注解&#xff0c;最后介绍Web配置&#xff0c;以便让读者对使用Spring Boot开发Web系统有初步的了解。…

微服务sleuth+zipkin---链路追踪+nacos配置中心

目录 1.分布式链路追踪 1.1.链路追踪Sleuth介绍 1.2.如何完成sleuth 1.3.zipkin服务器 2.配置中心 2.1.常见配置中心组件 2.2.微服务集群共享一个配置文件 2.2.1实时刷新--配置中心数据 2.2.2.手动写一个实时刷新的配置类 ----刷新配置文件 2.3.多个微服务公用一个配…

前端是不是快没了?

前言 可能是近些年前端的就业行情不好让你产生了这样的错觉&#xff1f;首先明确一点是我们不能拿市场就业、招聘的情况来判断一个行业的存亡&#xff0c;前端在目前仍然是有着比较大的需求&#xff0c;包括是在网页端、移动端、小程序方面&#xff0c;企业对于这些方面的需求…

msvcp140.dll丢失怎么弄?分享几个最靠谱的解决方法

当你在运行某个程序或游戏时&#xff0c;突然收到一个错误提示&#xff0c;提示你的计算机缺少msvcp140.dll文件。这意味着你的计算机中缺少一个重要的系统文件&#xff0c;可能会导致程序无法正常运行。下面是一些详细的解决方法&#xff0c;帮助你解决msvcp140.dll丢失的问题…

【力扣算法15】之 17. 电话号码的字母组合 python

文章目录 问题描述示例1示例2示例 3提示 思路分析代码分析完整代码详细分析运行效果截图调用示例运行结果 完结 问题描述 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下&#xff08;与电话按键…

获取微信服务器IP地址

获取微信服务器IP地址 如果公众号基于安全等考虑&#xff0c;需要获知微信服务器的IP地址列表&#xff0c;以便进行相关限制&#xff0c;可以通过该接口获得微信服务器IP地址列表或者IP网段信息。 由于出口IP及入口IP可能存在变动&#xff0c;建议用户每天请求接口1次&#x…