react中的useState和useImmer的用法

文章目录

  • 一、useState
    • 1. 更新基本类型数据
    • 2. 更新对象
    • 3. 更新嵌套对象
    • 4. 更新数组
    • 5.更新数组对象
  • 二、Immer
    • 1. 什么是Immer
    • 2. 使用use-immer更新嵌套对象
    • 3. 使用useImmer更新数组内部的对象

一、useState

react中文官网教程

1. 更新基本类型数据

在函数式组件中,可以使用 useState 这个 Hook 来定义和管理组件的状态。useState 接受一个初始状态作为参数,并返回一个包含 state 和更新 state 的方法的数组。

下面是一个例子,展示了如何在函数式组件中定义自己的 state:

import React, { useState } from "react";function MyComponent() {// 定义一个名为 count 的 state 变量,并将初始值设置为 0const [count, setCount] = useState(0);const handleClick = () => {setCount(count + 1);};return (<div><p>Count: {count}</p><button onClick={handleClick}>Increase Count</button></div>);
}export default MyComponent;

在上面的例子中,我们使用 useState 创建了一个名为 count 的状态变量,并将其初始值设为 0。然后,我们将 count 的值展示在 <p> 元素中,并在按钮的点击事件中调用 setCount 来更新 count 的值。

每当我们调用 setCount 来更新 count 的值时,React 会重新渲染组件并传递更新后的值给 count

2. 更新对象

在函数式组件中使用useState更新state中的对象可以通过以下步骤:

  1. 导入useState:
import React, { useState } from 'react';
  1. 创建一个对象作为初始状态(state):
const initialState = { name: 'John', age: 30, email: 'john@example.com' };
  1. 在组件内部使用useState钩子声明state:
const [person, setPerson] = useState(initialState);

这里person是状态对象,setPerson是一个更新状态的函数。useState(initialState)是useState的初始值参数。

  1. 在组件中使用状态对象:
return (<div><p>Name: {person.name}</p><p>Age: {person.age}</p><p>Email: {person.email}</p></div>
);
  1. 使用setPerson函数来更新状态对象的值:
const updateEmail = () => {setPerson({ ...person, email: 'updated@example.com' });
};

这里使用了ES6的展开语法(spread syntax)来复制现有的person对象,并更新email属性的值。

  1. 在组件中调用updateEmail函数来更新状态:
<button onClick={updateEmail}>Update Email</button>

完整的示例代码如下:

import React, { useState } from 'react';const App = () => {const initialState = { name: 'John', age: 30, email: 'john@example.com' };const [person, setPerson] = useState(initialState);const updateEmail = () => {setPerson({ ...person, email: 'updated@example.com' });};return (<div><p>Name: {person.name}</p><p>Age: {person.age}</p><p>Email: {person.email}</p><button onClick={updateEmail}>Update Email</button></div>);
};export default App;

通过点击"Update Email"按钮,可以更新email属性的值为"updated@example.com"。

在React的函数式组件中使用useState来更新一个对象的state时,有几个注意点需要特别注意

  1. useState函数仅仅是按照传入的初始值来初始化state,并不会合并对象。因此,在更新state时,需要先使用解构方式取出旧的对象属性值,然后再设置新的对象属性值。

  2. 由于useState是按照值的变化来判断是否重新渲染组件的,因此在更新state时,需要保证每一次更新都是返回一个新的对象。直接对原对象进行修改并返回会导致state没有发生变化,从而不会触发重新渲染。

  3. 可以使用展开运算符扩展现有对象,再进行属性的更改。这样可以确保每次都返回一个新的对象。

为什么要注意这些点呢?

首先,useState是基于值的比较来判断是否重新渲染组件的,如果不注意每次都返回一个新的对象,可能会导致state没有发生变化,从而不会触发重新渲染,无法更新组件视图。

其次,由于函数式组件没有实例的概念,每次组件渲染都是独立的,因此无法像类组件中使用this.setState那样自动合并对象属性。因此,在更新state时,需要手动合并旧的对象属性值和新的对象属性值,以确保不丢失任何旧的state属性。

最后,使用展开运算符扩展对象的方式可以确保每次都返回一个全新的对象,这样可以避免直接对原对象进行修改而导致state没有发生变化的问题。

3. 更新嵌套对象

在React的函数式组件中使用useState更新state中的嵌套对象,可以使用扩展运算符(spread operator)来实现。

举例说明,假设有一个包含嵌套对象的state,如下所示:

const [state, setState] = useState({name: "John",age: 30,address: {street: "123 Main St",city: "New York",state: "NY"}
});

要更新state中的嵌套对象,可以使用useState的setState函数,传递一个新的对象,并使用扩展运算符将原有的state进行展开,再覆盖需要更新的属性。例如,要更新address对象的city属性,可以使用以下代码:

setState({...state,address: {...state.address,city: "Los Angeles"}
});

上面的代码首先使用扩展运算符将原有的state展开,然后再针对需要更新的嵌套对象进行展开,并更新特定的属性。在本例中,我们更新了address对象的city属性,将其值从"New York"更新为"Los Angeles"。

完整的示例代码如下所示:

import React, { useState } from "react";function App() {const [state, setState] = useState({name: "John",age: 30,address: {street: "123 Main St",city: "New York",state: "NY"}});const updateCity = () => {setState({...state,address: {...state.address,city: "Los Angeles"}});};return (<div><p>Name: {state.name}</p><p>Age: {state.age}</p><p>Street: {state.address.street}</p><p>City: {state.address.city}</p><p>State: {state.address.state}</p><button onClick={updateCity}>Update City</button></div>);
}export default App;

在上述示例中,我们首先使用useState定义了包含嵌套对象的state,然后在组件中显示了state中的属性。最后,我们使用一个按钮来调用updateCity函数,该函数会更新state中的嵌套对象。点击按钮后,更新后的city属性值将显示为"Los Angeles"。

4. 更新数组

在函数式组件中使用useState来更新state中的数组,可以通过结构赋值的方式获取数组和更新数组的函数。一般情况下,使用useState更新数组时需要注意以下几点:

  1. 为了保持state的不可变性,应该使用数组的展开运算符(spread operator)来创建一个新的数组。

  2. 当更新数组时,需要将要更新的元素和其余元素区分开来。通常使用Array.map函数来遍历数组,并找到要更新的元素。

  3. 可以使用Array.filter函数过滤数组中的元素,从而可以删除特定的元素。

  4. 注意在更新数组时,在判断相等性时使用严格相等运算符(===),而不是用“浅比较”运算符(==)
    在这里插入图片描述

下面是一个更新数组的例子:

import React, { useState } from "react";function Example() {const [list, setList] = useState([1, 2, 3, 4, 5]);const handleUpdate = () => {// 通过展开运算符创建一个新的数组,并更新数组的第一个元素setList([...list.slice(0, 1), 100, ...list.slice(2)]);};const handleDelete = (item) => {// 使用filter过滤数组,删除特定的元素setList(list.filter((el) => el !== item));};return (<div><ul>{list.map((item) => (<li key={item}>{item}<button onClick={() => handleDelete(item)}>删除</button></li>))}</ul><button onClick={handleUpdate}>更新</button></div>);
}export default Example;

在这个例子中,list是一个包含数字的数组。点击列表项后的“删除”按钮会删除相应的元素,点击“更新”按钮会将数组的第一个元素更新为100。每次更新数组时,使用展开运算符创建一个新的数组,并把更新的元素插入到适当的位置,这样可以保持state的不可变性。在删除元素时,使用filter函数过滤掉特定的元素。

5.更新数组对象

在函数式组件中使用 useState 来更新 state 数组中的内部对象,可以使用解构赋值的方式来获取数组中的指定对象,并使用 useState 来更新该对象的属性。

首先,在函数式组件中使用 useState 定义一个状态变量,可以设置初始状态为一个包含内部对象的数组。例如,使用以下代码定义一个状态变量 items,并设置初始状态为一个包含两个内部对象的数组:

const [items, setItems] = useState([{ name: "apple", quantity: 1 },{ name: "banana", quantity: 2 }
]);

然后,通过解构赋值的方式获取数组中的指定对象,并使用 useState 更新该对象的属性。例如,通过以下代码获取数组中的第一个对象 item 并更新其 name 属性:

const [item, setItem] = useState(items[0]);const handleChangeName = () => {setItem(prevItem => ({ ...prevItem, name: "orange" }));
};

在上述代码中,setItem 函数通过接收一个回调函数来更新 item 对象的属性。该回调函数使用展开运算符 ... 将之前的属性拷贝到一个新的对象中,并更新 name 属性为 "orange"

需要注意的是,在更新数组时,不能直接修改数组中的对象。要更新数组中的对象,需要先拷贝数组,然后再更新其中的对象。可以使用 Array.map() 方法来拷贝数组并更新其中的对象。例如,使用以下代码将数组中的第一个对象的 name 属性改为 "orange"

const updatedItems = items.map((item, index) => {if (index === 0) {return { ...item, name: "orange" };}return item;
});setItems(updatedItems);

上述代码中,Array.map() 方法遍历数组,当索引为 0 的时候,返回一个新的对象,并更新其 name 属性为 "orange";否则,返回原来的对象。然后,将得到的新数组 updatedItems 设置为新的状态值。

二、Immer

1. 什么是Immer

Immer是一个JavaScript库,用于管理不可变状态。它通过基于原始状态创建一个新的状态树来实现不可变性。它提供了一种简单而直观的方式来处理复杂的状态更新逻辑,使代码更易于理解和维护。Immer可以与任何JavaScript框架或库一起使用,并且对于处理大型数据结构和深层嵌套的对象非常有用。它是一个流行的工具,用于管理JavaScript应用程序中的状态。

在React的函数式组件中,推荐使用Immer来处理复杂的数据state,特别是深层嵌套的数组对象,有以下几个原因:

  1. 操作不可变数据更加方便:Immer提供了一种简洁的方式来直接对不可变数据进行修改。通过使用Immer的produce函数,可以在不直接修改原始数据的情况下,创建一个可变的草稿副本,并且在草稿上进行所有的更改操作。这样可以避免因为直接修改原始数据而导致的引用问题和副作用问题。

  2. 性能优化:Immer采用了一种优化技术,称为“结构共享”,它能够在不实际复制数据的情况下实现不可变数据的修改。这种技术可以大大提高性能,特别是对于大型、深层嵌套的数据结构。

  3. 减少模板嵌套深度:在处理深层嵌套的数组对象时,使用Immer可以减少模板嵌套的深度。因为Immer提供了一种更简洁、更直观的方式来修改深层嵌套的数据,这能够提高代码的可读性和可维护性。

总之,使用Immer可以帮助我们更方便地处理复杂的数据state,尤其是深层嵌套的数组对象。它简化了对不可变数据的操作,并提供了性能优化的机制,使得我们能够更加高效地开发React应用。

2. 使用use-immer更新嵌套对象

在React的函数式组件中,可以使用use-immer库来更新嵌套对象的state。use-immer是基于Immer库的React Hook封装,它可以方便地进行不可变状态更新。

以下是一个示例,展示如何使用use-immer更新嵌套对象的state:

首先,安装use-immer库:

npm install use-immer

然后,导入useImmer函数并在函数式组件中使用它:

import React, { useState } from 'react';
import { useImmer } from 'use-immer';function App() {const [state, setState] = useImmer({user: {name: 'John',age: 25}});// 更新嵌套对象的示例函数const updateUserName = () => {setState(draft => {draft.user.name = 'Tom';});};return (<div><h1>{state.user.name}</h1><p>{state.user.age}</p><button onClick={updateUserName}>Update Name</button></div>);
}export default App;

在上面的示例中,我们使用useState和useImmer来声明和初始化state。state是一个嵌套对象,包含一个user对象。然后,我们在updateUserName函数中使用setState函数来更新嵌套对象的state。在setState的回调函数中,我们可以使用draft参数来修改状态。

使用use-immer库的好处是,我们可以在回调函数中直接修改draft对象,就像在原始状态上进行修改一样。useImmer会负责处理不可变性,最终生成一个新的状态,并将其应用于组件。

以上是使用use-immer库在React的函数式组件中更新嵌套对象状态的示例。可以根据实际需求进行相应的修改和扩展。

3. 使用useImmer更新数组内部的对象

可以使用useImmer hook结合immer来更新函数式组件中数组内部的对象。useImmer hook是在React中使用Immer库的推荐方式。

以下是一个示例,说明如何使用useImmer更新数组内部的对象:

import React, { useState } from 'react';
import { useImmer } from 'use-immer';const MyComponent = () => {// 使用useState hook创建数组状态const [data, setData] = useState([{ id: 1, name: 'John' },{ id: 2, name: 'Jane' },{ id: 3, name: 'Bob' },]);// 使用useImmer hook创建可变的数据副本draft和更新函数setDraftconst [draft, setDraft] = useImmer(data);// 更新对象的名称const updateName = (id, name) => {setDraft(draft => {// 使用immer的produce函数来更新draftconst item = draft.find(item => item.id === id);if (item) {item.name = name;}});};return (<div>{draft.map(item => (<div key={item.id}><span>{item.name}</span>{/* 在组件中触发更新名称的函数 */}<button onClick={() => updateName(item.id, 'Updated Name')}>Update Name</button></div>))}</div>);
};export default MyComponent;

在上面的代码中,我们首先使用useState hook创建了一个数组状态data,然后使用useImmer hook创建了一个可变的数据副本draft和一个更新函数setDraft。在更新函数中,我们使用immer的produce函数来更新draft,修改特定ID对应的对象的名称。

在组件的返回值中,我们使用draft.map循环遍历数组内部的对象,显示每个对象的名称,并使用按钮来触发更新的函数。

当你点击"Update Name"按钮时,会更新draft中特定ID对应的对象的名称,由于draft是可变的,所以React会自动更新组件的渲染。

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

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

相关文章

IPv6+ 3.0关键技术解析与应用实践探索

IPv6作为面向5G和云计算的智能IP技术&#xff0c;其核心是以IPv6技术架构为底座&#xff0c;并基于用户的新兴业务进行创新发展而来的。任何一项技术创新的背后都有一只看不见的推手-用户的需求&#xff0c;也就是用户的业务发展所需&#xff0c;进一步来说是用户的应用系统在驱…

【广州华锐互动】牛顿运动定律VR虚拟教学软件

在科技日新月异的今天&#xff0c;虚拟现实&#xff08;VR&#xff09;技术已经逐渐渗透到各个领域&#xff0c;为我们带来了前所未有的沉浸式体验。在教育领域&#xff0c;VR技术的应用也日益广泛&#xff0c;尤其是在物理教学中&#xff0c;牛顿运动定律VR虚拟教学软件为学生…

分析Python招聘数据,可视化展示招聘信息详情

嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! python更多源码/资料/解答/教程等 点击此处跳转文末名片免费获取 一. 数据来源分析 明确需求 明确采集网站以及数据内容 数据: 职位信息 网址: https://we.51job.com/pc/search?keywordpython&searchType3&sortType0&am…

Python通过pyecharts对爬虫房地产数据进行数据可视化分析(一)

一、背景 对Python通过代理使用多线程爬取安居客二手房数据&#xff08;二&#xff09;中爬取的房地产数据进行数据分析与可视化展示 我们爬取到的房产数据&#xff0c;主要是武汉二手房的房源信息&#xff0c;主要包括了待售房源的户型、面积、朝向、楼层、建筑年份、小区名称…

删除Win11文件管理器左侧的‘主文件夹‘和‘图库‘的链接.

删除Win11文件管理器左侧的主文件夹和图库的链接.删除步骤&#xff1a; * 1. win r 打开运行&#xff0c; 输入"regedit"打开注册表. * 2. 删除注册表: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Desktop\NameSpace_xxxxxxxNameSpace…

使用WebStorm创建和配置TypeScript项目

创建 这里我用的是WebStorm 2019.2.2版本 首先&#xff0c;创建一个空项目 File -> New -> Project->Empty Project生成配置文件 自动配置&#xff1a; 打开终端输入tsc --init&#xff0c;即可自动生成tsconfig.json文件 手动配置&#xff1a; 在项目根目录下新建一…

Capacitor 打包 h5 到 Android 应用,uniapp https http net::ERR_CLEARTEXT_NOT_PERMITTED

Capacitor 打包 h5 到 Android 应用&#xff0c;uniapp https http net::ERR_CLEARTEXT_NOT_PERMITTED capacitor 官网&#xff1a; https://capacitorjs.com/docs/ 项目上需要做一个 app&#xff0c;而这个 app 是用 uniapp 做的&#xff0c;里面用到了一个依赖 dom 的库&…

腾讯云轻量应用服务器“镜像”怎么选择合适?

腾讯云轻量应用服务器镜像怎么选择&#xff1f;如果是用来搭建网站可以选择宝塔Linux面板腾讯云专享版&#xff0c;镜像系统根据实际使用来选择&#xff0c;腾讯云百科txybk.com来详细说下腾讯云轻量应用服务器镜像的选择方法&#xff1a; 腾讯云轻量应用服务器镜像选择 轻量…

Ansys Speos|Optimization小工具快速优化设计

概述 优化是一个有助于找到一个光学系统的最佳解决方案的实验过程&#xff0c;它主要是利用参数的变化而试图达到预期的结果。在Speos 2023 R2中提供三种可供选择的方法来执行此类分析。第一个是基于workbench创建的优化&#xff0c;可以参考文章&#xff08;基于Ansys Workben…

SQL注入思路扩展

目录 一、资产搜集 二、开始sql注入常规流程 三、sqlmap验证 总结&#xff1a;测试sql注入的时候不要只局限于明文传输&#xff0c;也要注意编码或者加密后的值。 还没看够&#xff1f;欢迎关注&#xff0c;带你走进黑客世界&#xff0c;下面也有免费的靶场视频 一、资产搜…

springboot整合postgresql

使用docker安装postgres 简单起见&#xff0c;这里用docker来安装postgresql docker pull postgresdocker run --name postgres \-e POSTGRES_PASSWORD123456 \-p 5432:5432 \-v /usr/local/docker/postgresql/data:/var/lib/postgresql/data \-d postgrespostgres客户端 pg…

一文了解什么是JWT 与sessions

​session 和 JSON Web 令牌 (JWT) 是在调用之间维护此身份验证状态的两种最流行的方法。两者各有利弊&#xff0c;在它们之间进行选择需要了解这些权衡以及它们与应用程序的特定需求之间的关系。 一、基于session的身份验证 在基于session的身份验证&#xff08;也称为基于 c…

粤嵌实训医疗项目--day04(Vue + SpringBoot)

往期回顾 粤嵌实训医疗项目--day03&#xff08;Vue SpringBoot&#xff09;-CSDN博客粤嵌实训医疗项目day02&#xff08;Vue SpringBoot&#xff09;-CSDN博客粤嵌实训医疗项目--day01&#xff08;VueSpringBoot&#xff09;-CSDN博客 目录 一、用户详细信息查询 (查询信息与…

拿下国家级信创认证 中科驭数KPU SWIFT-2200N成为国内首款满足金融业严苛要求的DPU产品

近日&#xff0c;中科驭数KPU SWIFT-2200N低时延DPU卡&#xff0c;在中国人民银行旗下金融信创生态实验室完成测试并取得测试报告&#xff0c;这意味着中科驭数低时延网络代表性产品的应用领域从证券进一步拓展到了银行业&#xff0c;成为国内首款满足金融行业严苛要求的DPU产品…

无法查看 spring-boot-starter-parent的pom.xml

1. idea版本&#xff1a;2022.3 2. 使用Spring Initializr创建一个简单的spring-boot项目&#xff0c;发现无法查看 spring-boot-starter-parent的pom.xml ctrl鼠标左键 和 ctrl B 都无法进入 3. 解决&#xff1a;清除缓存重启&#xff08;&#x1f927;&#x1f630;&#…

服务器基础

目录 服务器介绍&#xff1a; 服务器定义&#xff1a; 服务器特点&#xff1a; 服务器架构&#xff1a; 按硬件形态的服务器分类&#xff1a; 华为TaiShan 200服务器的硬件结构&#xff1a; 服务器关键技术&#xff1a; IPMI协议&#xff08;Intelligent Platform Manag…

torch.nn中有哪些损失函数?

在PyTorch库的torch.nn模块中&#xff0c;提供了许多预定义的损失函数&#xff0c;用于不同的机器学习任务。以下是一些常见的损失函数&#xff1a; MSELoss&#xff08;均方误差损失&#xff09;: 常用于回归问题&#xff0c;计算预测值与真实值之间的平均平方误差。 import…

frp-内网穿透部署-ubuntu22服务器-windows server-详细教程

文章目录 1.下载frp2.配置服务器2.1.配置frps.ini文件2.2.设置服务文件2.3.设置开机自启和服务操作2.4.后台验证2.5.服务器重启 3.配置本地window3.1.frpc配置3.2.添加开机计划启动3.3.控制台启动隐藏窗口 4.centos防火墙和端口3.1.开放端口3.2.查看端口 5.关闭进程5.1.杀死进程…

经典目标检测神经网络 - RCNN、SSD、YOLO

文章目录 1. 目标检测算法分类2. 区域卷积神经网络2.1 R-CNN2.2 Fast R-CNN2.3 Faster R-CNN2.4 Mask R-CNN2.5 速度和精度比较 3. 单发多框检测&#xff08;SSD&#xff09;4. YOLO 1. 目标检测算法分类 目标检测算法主要分两类&#xff1a;One-Stage与Two-Stage。One-Stage与…

JavaScript_Pig Game重置游戏

//重置游戏 btnNew.addEventListener(click, function () {score0El.textContent 0;score1El.textContent 0;current0El.textContent 0;current1El.textContent 0;player0El.classList.remove(player--winner);player1El.classList.remove(player--winner);player0El.class…