【React】useState:状态更新规则详解
文章目录
- 一、基本用法
- 二、直接修改状态 vs 使用 `setState` 更新状态
- 三、对象状态的更新
- 四、深层次对象的更新
- 五、函数式更新
- 六、优化性能的建议
在 React 中,
useState
是一个非常重要的 Hook,用于在函数组件中添加状态管理功能。正确理解和使用useState
更新状态的规则,对于构建高效和可维护的 React 应用至关重要。本文将通过详细的解释和代码示例,帮助您深入理解useState
的状态更新规则。
一、基本用法
useState
的基本用法非常简单。它返回一个状态变量和一个更新该状态的函数:
import { useState } from 'react';function App() {const [count, setCount] = useState(0);const handleClick = () => {setCount(count + 1);};return (<div><button onClick={handleClick}>{count}</button></div>);
}export default App;
在这个例子中,useState(0)
初始化了一个状态变量 count
,初始值为 0,setCount
是用于更新 count
的函数。每次点击按钮,count
的值都会加 1,并触发组件重新渲染。
二、直接修改状态 vs 使用 setState
更新状态
在使用 useState
时,直接修改状态变量不会触发组件重新渲染。只有通过 setState
函数更新状态,React 才会知道状态发生了变化,并触发重新渲染:
import { useState } from 'react';function App() {const [count, setCount] = useState(0);const handleClick = () => {// 直接修改不会触发视图更新// count++;// console.log(count);// 正确写法:使用 setCountsetCount(count + 1);};return (<div><button onClick={handleClick}>{count}</button></div>);
}export default App;
在上述代码中,如果我们直接修改 count
的值,如 count++
,视图不会更新,因为 React 不知道状态已经改变。正确的做法是使用 setCount
更新状态,这样 React 才能检测到状态变化并重新渲染组件。
三、对象状态的更新
使用 useState
管理对象状态时,需要注意不要直接修改对象,而是通过创建新对象来更新状态。直接修改对象属性不会触发组件重新渲染:
import { useState } from 'react';function App() {const [form, setForm] = useState({ name: 'jack' });const changeForm = () => {// 错误写法:直接修改对象// form.name = 'john';// 正确写法:创建一个新对象setForm({...form,name: 'john'});};return (<div><button onClick={changeForm}>修改form {form.name}</button></div>);
}export default App;
在这个例子中,如果我们直接修改 form.name
的值,如 form.name = 'john'
,视图不会更新。正确的做法是通过 setForm
创建一个新对象来更新状态。
四、深层次对象的更新
当状态是一个嵌套的深层次对象时,更新状态需要更加谨慎。确保每个层次的对象都创建一个新的副本,才能保证 React 检测到状态变化并重新渲染组件:
import { useState } from 'react';function App() {const [user, setUser] = useState({name: 'jack',address: {city: 'New York',country: 'USA'}});const changeCity = () => {setUser({...user,address: {...user.address,city: 'Los Angeles'}});};return (<div><button onClick={changeCity}>修改城市 {user.address.city}</button></div>);
}export default App;
在这个例子中,我们更新了嵌套对象 address
的 city
属性。通过创建 user
和 address
的新副本,React 能够检测到状态变化并重新渲染组件。
五、函数式更新
当新状态依赖于之前的状态时,使用函数式更新可以避免潜在的竞态条件。函数式更新接收一个函数,该函数的参数是之前的状态,返回新的状态值:
import { useState } from 'react';function App() {const [count, setCount] = useState(0);const handleClick = () => {setCount(prevCount => prevCount + 1);};return (<div><button onClick={handleClick}>{count}</button></div>);
}export default App;
在这个例子中,setCount
接收一个函数 prevCount => prevCount + 1
。这个函数的参数 prevCount
是之前的状态值,返回新的状态值。这种方式可以确保状态更新的正确性,尤其是在多个状态更新操作可能同时发生时。
六、优化性能的建议
-
避免不必要的状态更新
确保只有在状态确实发生变化时才调用
setState
,以避免不必要的重新渲染。const handleClick = () => {if (count !== newCount) {setCount(newCount);} };
-
使用 React.memo 进行性能优化
对于函数组件,可以使用
React.memo
进行性能优化,使组件在相同的 props 下不重新渲染。const MyComponent = React.memo(({ value }) => {return <div>{value}</div>; });
-
避免在 render 方法中定义函数
在
render
方法中定义函数会导致每次渲染时都创建新的函数实例,影响性能。将函数定义在组件外或使用useCallback
Hook 缓存函数。import { useCallback } from 'react';const handleClick = useCallback(() => {setCount(prevCount => prevCount + 1); }, []);
.
相关文章:

【React】useState:状态更新规则详解
文章目录 一、基本用法二、直接修改状态 vs 使用 setState 更新状态三、对象状态的更新四、深层次对象的更新五、函数式更新六、优化性能的建议 在 React 中,useState 是一个非常重要的 Hook,用于在函数组件中添加状态管理功能。正确理解和使用 useState…...
C#中的异步编程:Task、Await 和 Async
public async void DoSth() {await Task.Run(() > {//...DoSth...}); } ①函数的返回类型前加上: async ②函数内加上: await Task.Run(() > { }); ③在上面{ ... } 内添加要处理的程序代码, 这样运行到 DoSth() 函数就…...

SSRF-labs-master靶场
目录 file_get_content.php sql_connect.php download.php dns-spoofing.php dns_rebinding.php 访问链接 http://127.0.0.1/SSRF/# file_get_content.php 在编程语言中,有一些函数可以获取本地保存文件的内容。这些功能可能能够从远程URL以及本地文件 如果没…...

HBuilder X中配置vue-cli项目和UI库
目录 一.前端项目结构 二.在HBuilder X中搭建vue-cli项目 1. 安装node.js前端环境 2. HBuilder X创建一个vue-cli项目 3. vue-cli项目结构 4. 如何运行前端项目 5. 创建组件 6. 组件路由(页面跳转) 6.1 创建router目录 6.2 使用路由 6.3 在main.js中配置路由 6.4 路…...

如何用PostMan按照规律进行循环访问接口
①设置动态变量 步骤一: 设置环境变量 1. 创建环境变量集合 在 Postman 左上角选择 "环境",然后点击 "添加" 来创建一个新的环境变量集合。给它起一个名称,比如 "uploadDemo". 2. 添加初始变量 在新创建的环境变量集…...

稳态准直太阳光模拟器仪器光伏电池组件IV测试
太阳能模拟器电池IV测试仪、单体测试仪,配备匹配标准的AAA Class稳态太阳能模拟器及相关测试附件,可对太阳能电池片的IV性能进行测量、分级分选等; 介绍 AAA class太阳光模拟器整合完整的IV测量系统,针对各种太阳能电池的性能&a…...
vue3 reactive原理(二)-代理Set和Map及ref原理
Set和Map类型的数据也属于异质对象,它们有特定的属性和方法用来操作自身。因此创建代理时,针对特殊的方法需要特殊的对待。 Vue 的ref 是基于reactive函数实现的,它在其基础上,增加了基本类型的响应性、解决reactive在解构时丢失…...

Python自然语言处理库之NLTK与spaCy使用详解
概要 自然语言处理(NLP)是人工智能和数据科学领域的重要分支,致力于让计算机理解、解释和生成人类语言。在Python中,NLTK(Natural Language Toolkit)和spaCy是两个广泛使用的NLP库。本文将详细介绍NLTK和spaCy的特点、功能及其使用方法,并通过具体示例展示如何使用这两…...

Hive-内部表和外部表
区别 内部表实例 准备数据 查看数据 删除数据 外部表实例 准备数据 查看数据 删除数据 区别 内部表:管理元数据(记录数据的文件和目录的信息)和数据。当删除内部表时,会删除数据和表的元数据,所以当多个表关…...
Java并发编程(三)
Java并发编程 1、什么是 Executors 框架 Executors框架是一个根据一组执行策略调用,调度,执行和控制的异步任务的框架。 无限制的创建线程会引起应用程序内存溢出。所以创建一个线程池是个更好的的解决方案,因为可以限制线程的数量并且可以…...

Flink Doirs Connector 常见问题:Doris目前不支持流读
常见问题 Doris Source 在数据读取完成后,流为什么就结束了? 目前 Doris Source 是有界流,不支持 CDC 方式读取。 问题:对于 Flink Doris DataStream,Flink 想要在 流式读取 Doirs / 实时读 Doris,目前读…...

期末复习资料——计算机系统基础
第一章 1、下列关于机器字长、指令字长和存储字长的说法中,正确的时_②、③_ ①三者在数值上总是相等的。②三者在数值上可能不相等。③存储字长是存放在一个存储单元中的二进制代码位数。④数据字长就是MDR的位数。 机器字长、指令字长和存储字长,三…...
一天搞定Recat(5)——ReactRouter(上)【已完结】
Hello!大家好,今天带来的是React前端JS库的学习,课程来自黑马的往期课程,具体连接地址我也没有找到,大家可以广搜巡查一下,但是总体来说,这套课程教学质量非常高,每个知识点都有一个…...

TCP/IP 网络模型详解(二)之输入网址到网页显示的过程
当键入网址后,到网页显示,其间主要发生了以下几个步骤: 一、解析URL 下图是URL各个元素所表示的意义: 右边蓝色部分(文件的路径名)可以省略。当没有该数据时,代表访问根目录下事先设置的默认文…...

【k8s故障处理篇】calico-kube-controllers状态为“ImagePullBackOff”解决办法
【k8s故障处理篇】calico-kube-controllers状态为“ImagePullBackOff”解决办法 一、环境介绍1.1 本次环境规划1.2 kubernetes简介1.3 kubernetes特点二、本次实践介绍2.1 本次实践介绍2.2 报错场景三、查看报错日志3.1 查看pod描述信息3.2 查看pod日志四、报错分析五、故障处理…...

SAP PP学习笔记31 - 计划运行的步骤2 - Scheduling(日程计算),BOM Explosion(BOM展开)
上一章讲了计划运行的5大步骤中的前两步,计算净需求和计算批量大小。 SAP PP学习笔记30 - 计划运行的步骤1 - Net requirements calculation 计算净需求(主要讲了安全库存要素),Lot-size calculation 计算批量大小-CSDN博客 本章继续讲计划运行的后面几…...

[vue3]配置@指向src
在vit.config.ts里的export default defineConfig添加以下语句 resolve: {alias: {"": "/src", // 配置指向src目录},},...

【多模态大模型】 BLIP in ICML 2022
一、引言 论文: BLIP: Bootstrapping Language-Image Pre-training for Unified Vision-Language Understanding and Generation 作者: Salesforce Research 代码: BLIP 特点: 该方法分别使用ViT和BERT进行图像和文本特征提取&am…...
Flutter开发Dart 中的 mixin、extends 和 implements
目录 前言 1.extends 2.implements 3.mixin 前言 在 Dart 中,mixin、extends 和 implements 是面向对象编程中常用的关键字,它们分别用于不同的继承和实现方式。理解它们的用法和区别对于编写高质量、可维护的 Dart 代码至关重要。本文…...

SAPUI5基础知识20 - 对话框和碎片(Dialogs and Fragments)
1. 背景 在 SAPUI5 中,Fragments 是一种轻量级的 UI 组件,类似于视图(Views),但它们没有自己的控制器(Controller)。Fragments 通常用于定义可以在多个视图中重用的 UI 片段,从而提…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

Qemu arm操作系统开发环境
使用qemu虚拟arm硬件比较合适。 步骤如下: 安装qemu apt install qemu-system安装aarch64-none-elf-gcc 需要手动下载,下载地址:https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x…...
怎么开发一个网络协议模块(C语言框架)之(六) ——通用对象池总结(核心)
+---------------------------+ | operEntryTbl[] | ← 操作对象池 (对象数组) +---------------------------+ | 0 | 1 | 2 | ... | N-1 | +---------------------------+↓ 初始化时全部加入 +------------------------+ +-------------------------+ | …...

DAY 45 超大力王爱学Python
来自超大力王的友情提示:在用tensordoard的时候一定一定要用绝对位置,例如:tensorboard --logdir"D:\代码\archive (1)\runs\cifar10_mlp_experiment_2" 不然读取不了数据 知识点回顾: tensorboard的发展历史和原理tens…...

SQL注入篇-sqlmap的配置和使用
在之前的皮卡丘靶场第五期SQL注入的内容中我们谈到了sqlmap,但是由于很多朋友看不了解命令行格式,所以是纯手动获取数据库信息的 接下来我们就用sqlmap来进行皮卡丘靶场的sql注入学习,链接:https://wwhc.lanzoue.com/ifJY32ybh6vc…...
AWS vs 阿里云:功能、服务与性能对比指南
在云计算领域,Amazon Web Services (AWS) 和阿里云 (Alibaba Cloud) 是全球领先的提供商,各自在功能范围、服务生态系统、性能表现和适用场景上具有独特优势。基于提供的引用[1]-[5],我将从功能、服务和性能三个方面进行结构化对比分析&#…...
npm install 相关命令
npm install 相关命令 基本安装命令 # 安装 package.json 中列出的所有依赖 npm install npm i # 简写形式# 安装特定包 npm install <package-name># 安装特定版本 npm install <package-name><version>依赖类型选项 # 安装为生产依赖(默认&…...

AI书签管理工具开发全记录(十八):书签导入导出
文章目录 AI书签管理工具开发全记录(十八):书签导入导出1.前言 📝2.书签结构分析 📖3.书签示例 📑4.书签文件结构定义描述 🔣4.1. 整体文档结构4.2. 核心元素类型4.3. 层级关系4.…...
Flask和Django,你怎么选?
Flask 和 Django 是 Python 两大最流行的 Web 框架,但它们的设计哲学、目标和适用场景有显著区别。以下是详细的对比: 核心区别:哲学与定位 Django: 定位: "全栈式" Web 框架。奉行"开箱即用"的理念。 哲学: "包含…...