react hooks--useState

news2024/11/15 17:43:07

概述

useState 可以使函数组件像类组件一样拥有 state,也就说明函数组件可以通过 useState 改变 UI 视图。那么 useState 到底应该如何使用,底层又是怎么运作的呢,首先一起看一下 useState 。

问题:Hook 是什么? 一个 Hook 就是一个特殊的函数,让你在函数组件中获取状态等 React 特性
使用模式:函数组件 + Hooks
特点:从名称上看,Hook 都以 use 开头

基本使用

  • 使用场景:当你想要在函数组件中,使用组件状态时,就要使用 useState Hook 了
  • 作用:为函数组件提供状态(state)
  • 使用步骤:
    1. 导入 useState 函数:import { useState} from 'react'
    2. 调用 useState 函数,并传入状态的初始值
    3. useState 函数的返回值中,拿到状态和修改状态的函数
    4. 在 JSX 中展示状态
    5. 在按钮的点击事件中调用修改状态的函数,来更新状态
  • 规则:
    • 只能在函数最外层调用 Hook。不要在循环、条件判断或者子函数中调用
    • 只能在 React 的函数组件中调用 Hook。不要在其他 JavaScript 函数中调用
  • useState接受唯一一个参数,在第一次组件被调用时使用来作为初始化值

使用数组解构简化

比如,要获取数组中的元素:

  1. 原始方式:索引访问
const arr = ['aaa', 'bbb']

const a = arr[0]  // 获取索引为 0 的元素
const b = arr[1]  // 获取索引为 1 的元素

  1. 简化方式:数组解构
    • 相当于创建了两个变量(可以是任意的变量名称)分别获取到对应索引的数组元素
const arr = ['aaa', 'bbb']
const [a, b] = arr

const [state, setState] = arr

  • 使用数组解构简化 useState 的使用
    • 约定:修改状态的函数名称以 set 开头,后面跟上状态的名称
// 解构出来的名称可以是任意名称
const [state, setState] = useState(0)
const [age, setAge] = useState(0)
const [count, setCount] = useState(0)

演示示例

父传子

App.js--父组件

import React from 'react'
import UseFun from './components/useFun'

export default function App() {
  let msg = '132'
  return (
    <div>
      <UseFun msg={msg}/>
    </div>
  )
}

src/components/useFun.js--子组件

import React from 'react'
import PropTypes from 'prop-types'

function useFun(props) {
  return (
    <div>{props.msg}</div>
  )
}

useFun.defaultProps = {
  msg: '456'
}

useFun.propTypes = {
  msg: PropTypes.string
}

export default  useFun

计数器

App.js

import React from 'react'
import UseFun from './components/UseFun'
import CountFun from './components/CountFun'

export default function App() {
  let msg = '132'
  return (
    <div>
      <CountFun />
    </div>
  )
}

components/CountFun.jsx

import React from 'react'
import { useState } from 'react';

export default function CountFun() {

  let [count, setCount] = useState(0)

  function changeCount(){
    setCount(count + 1)
  }
 
  return (
    <div>
      {/* 展示状态值 */}
      <h1>useState Hook - {count}</h1>
      {/* 点击按钮,让状态值 +1 */}
      <button onClick={changeCount}>+1</button>
      <button onClick={() => changeCount()}>+1</button>
    </div>
  )
}

或下面的做法也可以

import { useState } from 'react'

export default function const CountFun = () => {
  // 返回值是一个数组
  const stateArray = useState(0)

  // 状态值 -> 0
  const state = stateArray[0]
  // 修改状态的函数
  const setState = stateArray[1]

  return (
    <div>
      {/* 展示状态值 */}
      <h1>useState Hook -> {state}</h1>
      {/* 点击按钮,让状态值 +1 */}
      <button onClick={() => setState(state + 1)}>+1</button>
    </div>
  )
}
  • 参数:状态初始值。比如,传入 0 表示该状态的初始值为 0
    • 注意:此处的状态可以是任意值(比如,数值、字符串等),而 class 组件中的 state 必须是对象
  • 返回值:数组,包含两个值:1 状态值(state) 2 修改该状态的函数(setState)

useState详解

概述

状态的读取和修改:

状态的使用:1 读取状态 2 修改状态

  1. 读取状态:该方式提供的状态,是函数内部的局部变量,可以在函数内的任意位置使用
  2. 修改状态:
  • setCount(newValue) 是一个函数,参数表示:新的状态值
  • 调用该函数后,将使用新的状态值替换旧值
  • 修改状态后,因为状态发生了改变,所以,该组件会重新渲染

组件的更新过程:

函数组件使用 useState hook 后的执行过程,以及状态值的变化:

  • 组件第一次渲染:
    1. 从头开始执行该组件中的代码逻辑
    2. 调用 useState(0) 将传入的参数作为状态初始值,即:0
    3. 渲染组件,此时,获取到的状态 count 值为: 0
  • 组件第二次渲染:
    1. 点击按钮,调用 setCount(count + 1) 修改状态,因为状态发生改变,所以,该组件会重新渲染
    2. 组件重新渲染时,会再次执行该组件中的代码逻辑
    3. 再次调用 useState(0),此时 React 内部会拿到最新的状态值而非初始值,比如,该案例中最新的状态值为 1
    4. 再次渲染组件,此时,获取到的状态 count 值为:1

注意:useState 的初始值(参数)只会在组件第一次渲染时生效

也就是说,以后的每次渲染,useState 获取到都是最新的状态值。React 组件会记住每次最新的状态值!

注意点:

  • 在普通函数(方法)中,不能使用hooks
  • 在自定义的hooks中可以使用,自定义hooks必须以use开头

基本数据类型

引入useState

import { useState } from 'react';

在函数组件内部定义state数据

let [count, setCount] = useState(0);
let [name, setName] = useState('张三')

useState会返回一个数组,数组有两个值

  • 第一个值:代表state数据
  • 第二个值:更新这个state数据的一个函数,一般函数变量取名字通常是setXxx

可以定义多个 state值

修改数据:

function changeName() {
    setName('李四');
}

完整代码:

import React from 'react'
import { useState } from 'react';

function useFun(props) {
  let [msg, setMsg] = useState('张三')

  function changeMsg(){
    setMsg('李四')
  }

  return (
    <div>
      <p>msg:{msg}</p>
      <button onClick={changeMsg}>修改msg</button>
    </div>
  )
}

export default  useFun

引用数据类型

定义对象数据

let [user, setUser] = useState({
    name: 'zs',
    age: 20
})

修改对象

function changeUserName() {
    setUser({
        name: 'ls',
    })
}

这样修改对象,会导致其他属性丢失,因为它没有自动合并对象

正确方式:

function changeUserName() {
    setUser({
        ...user,
        name: 'ls',
    })
}

可以将整个对象解构扩展,然后将修改的属性覆盖原来属性

注意:

修改state数据第一个参数可以是函数

setUser((prevState) => {
    console.log(prevState)
    return {
        ...prevState,
        name: 'ls'
    }
})

这个函数和类组件的setState的第一个参数是一致的

修改数据函数没有第二个参数

修改数据的函数仍然是异步的,不是同步的。

完整代码:

import React from "react";
import { useState } from "react";

function useFun(props) {
  let [msg, setMsg] = useState("张三");
  let [user, setName] = useState({
    name: "zs",
    age: 20,
  });

  function changeMsg() {
    setMsg("李四");
  }

  const changeName = () => {
    // setName({
    //   ...user,
    //   name: 'ls'
    // })
    //或如下写法:
    setName((prevState) => {
      console.log(prevState);
      return {
        ...prevState,
        name: "ls",
      };
    });
  };

  return (
    <div>
      <p>msg:{msg}</p>
      <button onClick={changeMsg}>修改msg</button>
      <hr />
      <p>name::{user.name}</p>
      <p>age: {user.age}</p>
      <button onClick={changeName}>修改name</button>
    </div>
  );
}

export default useFun;

为函数组件添加多个状态

问题:如果一个函数组件需要多个状态,该如何处理?
回答:调用 useState Hook 多次即可,每调用一次 useState Hook 可以提供一个状态。
注意:useState Hook 多次调用返回的 [state, setState] 相互之间,互不影响。

注意:React Hooks 只能直接出现在 函数组件 中,不能嵌套在 if/for/其他函数中

否则就会报错:React Hook "useState" is called conditionally. React Hooks must be called in the exact same order in every component render

React 的 useState 这个 Hook 被条件性(放在一个条件判断中)的调用了。

React Hooks 必须要每次组件渲染时,按照相同的顺序来调用所有的 Hooks。

  • 为什么会有这样的规则? 因为 React 是按照 Hooks 的调用顺序来识别每一个 Hook,如果每次调用的顺序不同,导致 React 无法知道是哪一个 Hook
  • 通过开发者工具可以查看到。

如何监听 state 变化?

类组件 setState 中,有第二个参数 callback 或者是生命周期componentDidUpdate 可以检测监听到 state 改变或是组件更新。

那么在函数组件中,如何怎么监听 state 变化呢?这个时候就需要 useEffect 出场了,通常可以把 state 作为依赖项传入 useEffect 第二个参数 deps ,但是注意 useEffect 初始化会默认执行一次。

具体可以参考如下 Demo :

dispatch更新特点

上述讲的批量更新和 flushSync ,在函数组件中,dispatch 更新效果和类组件是一样的,但是 useState 有一点值得注意,就是当调用改变 state 的函数dispatch,在本次函数执行上下文中,是获取不到最新的 state 值的,把上述demo 如下这么改:

结果:0,0,0

原因很简单,函数组件更新就是函数的执行,在函数一次执行过程中,函数内部所有变量重新声明,所以改变的 state ,只有在下一次函数组件执行时才会被更新。所以在如上同一个函数执行上下文中,number 一直为0,无论怎么打印,都拿不到最新的 state 。

useState注意事项

在使用 useState 的 dispatchAction 更新 state 的时候,记得不要传入相同的 state,这样会使视图不更新。比如下面这么写:

如上例子🌰中,当点击按钮后,发现视图没有改变,为什么会造成这个原因呢?

在 useState 的 dispatchAction 处理逻辑中,会浅比较两次 state ,发现 state 相同,不会开启更新调度任务; demo 中两次 state 指向了相同的内存空间,所以默认为 state 相等,就不会发生视图更新了。

解决问题: 把上述的 dispatchState 改成 dispatchState({...state}) 根本解决了问题,浅拷贝了对象,重新申请了一个内存空间。

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

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

相关文章

【思博伦】史上最详细思博伦测试仪使用精讲(三)!图解超赞超详细!!!

目录 2.2.14 抓包过滤条件配置 2.2.14.1 配置抓Tx或Rx方向的包 2.2.14.2 添加自定义过滤条件 2.2.14.3 按照包类型配置Qualify Events 2.2.14.4 按照包类型配置Start Events ​​​​​​​2.2.14.5 按照包类型配置Stop Events ​​​​​​​2.2.15 端口计数器统计 ​​…

大数据处理技术:HBase的安装与基本操作

目录 1 实验名称 2 实验目的 3 实验内容 4 实验原理 5 实验过程或源代码 5.1 Hbase数据库的安装 5.2 创建表 5.3 添加数据、删除数据、删除表 5.4 使用Java操作HBase 6 实验结果 6.1 Hbase数据库的安装 6.2 创建表 6.3 添加数据、删除数据、删除表 6.4 使用Java操…

25嘉士伯笔试测评希音笔试测评秋招校招SHL笔试题型分享

25嘉士伯笔试测评用的SHL笔试测评题库&#xff0c;分为两部分&#xff1a; 综合能力部分有计算题 图形推理题 连线题 逻辑题 日历题等等&#xff0c;36min24道题&#xff0c;新手很难做完&#xff1b; 岗位匹配度测评分为8道综合能力性格测试题&#xff0c;给三个选项选出最符…

【系统架构师】-论文-2024-2009年系统架构师历年论文题目

2024年5月 大数据Lambda架构的应用与分析 云原生云上DevOps运维应用与分析 模型驱动软件开发方法与应用 论单元测试在软件回归测试中的应用和分析 2023年 论面向对象设计的应用与实现 论多数据源集成的应用与实现 论软件可靠性模型的设计与实现 论边缘计算技术的设计与实现 …

Java:抽象类和接口(1)

一 抽象类 1.什么是抽象类 在 Java SE 中&#xff0c;抽象类是一种用于为其他类提供通用行为的类。它允许你定义一组方法和字段&#xff0c;而具体的实现留给子类来完成。抽象类不能被实例化&#xff0c;必须通过继承它的子类来实现其抽象方法并进行实例化。 public abstrac…

MATLAB系列04:循环结构

MATLAB系列04&#xff1a;循环结构 4. 循环结构4.1 while循环4.2 for循环4.2.1 运算的细节4.2.2 break语句和continue语句4.2.3 嵌套循环 4.3 逻辑数组和向量化4.3.1 逻辑数组的重要性4.3.2 用 if/else 结构和逻辑数组创建等式 4.4 总结 4. 循环结构 循环(loop)是一种 MATLAB …

初识Linux · 进程(4)

目录 前言&#xff1a; 进程的状态 直接谈论进程的状态 僵尸进程和孤儿进程 纯理论部分 运行态&#xff1a; 阻塞态&#xff1a; 挂起态&#xff1a; 进程的优先级以及切换问题 切换&#xff1a; 优先级&#xff1a; 前言&#xff1a; 承接上文&#xff0c;进程1到…

CPU 和 GPU:为什么GPU更适合深度学习?

目录 什么是 CPU &#xff1f; 什么是 GPU &#xff1f; GPU vs CPU 差异性对比分析 GPU 是如何工作的 &#xff1f; GPU 与 CPU 是如何协同工作的 &#xff1f; GPU vs CPU 类型解析 GPU 应用于深度学习 什么是 CPU &#xff1f; CPU&#xff08;中央处理器&#xff09;…

二叉树链式结构遍历(指针、递归)

当二叉树不使用数组实现&#xff0c;而是使用链式结构&#xff0c;用指针将节点相连时&#xff0c; 二叉树便会衍生出很多问题&#xff0c;如前序遍历、中序遍历、后序遍历、层序遍历。 下面我将用递归的方法完成二叉树的遍历。 但在这之前&#xff0c;我们还得构造链式结构…

深入解析 Apache Ranger

一. 概述 1.什么是 Apache Ranger&#xff1f; Apache Ranger 是一个为大数据平台提供集中化安全管理的开源框架&#xff0c;专门用于确保 Hadoop 生态系统中的数据安全。Ranger 通过提供细粒度的访问控制和监控&#xff0c;帮助组织实现对数据的全面安全管理&#xff0c;确保…

第四天旅游线路预览——从换乘中心到观鱼台

第四天&#xff1a;从贾登峪到喀纳斯风景区入口&#xff0c;晚上住宿贾登峪&#xff1b; 换乘中心有4 路车&#xff0c;喀纳斯②号车&#xff0c;去观鱼台&#xff0c;路程时长约20分钟&#xff1b; 将上面的的行程安排进行动态展示&#xff0c;具体步骤见”Google earth stu…

7.Jmeter数据驱动(csv数据文件设置)+Jmeter数据库操作

一、Jmeter数据驱动 因为&#xff1a;工作中&#xff0c;有些公司一个接口就是一个吻用例&#xff0c;另外一些公司一个接口有几十个用例&#xff0c;就需要用到数据驱动。 特别注意&#xff1a;断言&#xff0c;如果有共同字段&#xff0c;那么就用json断言&#xff0c;如果没…

文档管理系统Mayan EDMS的安装

今天台风 “贝碧嘉” 在上海登陆&#xff0c;这名字起的那叫一个绝&#xff0c;听起来像是 卑鄙家&#xff0c; 说的就是这台风 卑鄙到家了 什么是 EDMS&#xff1f; EDMS 代表电子文档管理系统&#xff0c;它是 DMS 的更现代版本。DMS 是文档管理系统。一种用于存储、排序和分…

二叉树的前中后序遍历(非递归迭代实现)

1.二叉树的前序遍历 1.1 思路分析 前序遍历的顺序是根-左子树-右子树&#xff0c;所以首先从根节点开始&#xff0c;顺着访问左子树&#xff1a;1、2、4。此时&#xff0c;还剩下节点1、节点2、节点3的右子树没有访问。后面倒着访问节点1、2、4的右子树就行了。所以非递归的前…

解决跨境电商平台账号无法访问的常见问题

跨境电商的迅猛发展&#xff0c;越来越多的卖家选择在全球各大电商平台如亚马逊、eBay等进行商品销售。然而&#xff0c;在实际运营过程中&#xff0c;卖家经常会遇到账号无法访问、应用打不开等问题&#xff0c;导致业务受阻。本文将针对这些问题进行详细分析&#xff0c;并提…

【医疗影像】THE BEER-LAMBERT LAW

吸光度 A l o g 10 ( I 0 I ) A log_{10}(\frac{I_0} I) Alog10​(II0​​) 如果您了解光谱仪如何工作&#xff0c;您就会知道它使一系列波长的光穿过物质溶液&#xff08;样品cell&#xff09;&#xff0c;同样地&#xff0c;也会穿过溶剂&#xff08;参考cell&#xff09; …

信息安全工程师(5)域名与域名解析

一、域名 1. 定义与功能 域名&#xff08;Domain Name&#xff09;是互联网上用于标识网站或服务器地址的名称&#xff0c;由一串由点分隔的字符组成&#xff0c;如“example.com”。域名的主要功能是提供一种便于记忆和输入的地址形式&#xff0c;以代替难以记忆的IP地址。域名…

【Axure原型】B端系统登录注册页设计成这样,就不用跟小孩一桌了

前言 在B端后台中&#xff0c;登录注册页这个东西&#xff0c;因为感觉很简单&#xff0c;所以经常不被产品经理们重视。但是登录注册页作为一个后台系统的门面&#xff0c;直接影响用户第一印象&#xff0c;又是非常重要的存在。 登录注册页的价值 B端系统登录注册页是用户…

浸没边界法空间精度相关的论文的阅读笔记

Convergence proof of the velocity field for a stokes flow immersed boundary method https://doi.org/10.1002/cpa.20233 研究对象的选取 他这里为什么能够选取一个周期性边界的流场啊&#xff1f;为什么不是狄利克雷边界或者诺伊曼边界&#xff1f; 方形流场的边界值 …

【Linux】精通GDB:打造你的Linux调试超能力

&#x1f308; 个人主页&#xff1a;Zfox_ &#x1f525; 系列专栏&#xff1a;C从入门到精通 目录 一&#xff1a; &#x1f525; 什么是GDB / CGDB 二&#xff1a; &#x1f525; CGDB的安装 &#x1f34a; Linux-centos 三&#xff1a; &#x1f525; cgdb的使用背景 &#…