React 组件中 State 的定义、使用及正确更新方式
🌈个人主页:前端青山
🔥系列专栏:React篇
🔖人终将被年少不可得之物困其一生
依旧青山,本期给大家带来React篇专栏内容React 组件中 State 的定义、使用及正确更新方式
前言
在 React 应用开发中,state
是组件内部用来存储和管理数据的关键概念。它允许组件根据不同的状态展示不同的 UI。本文将详细介绍 state
的定义、使用方式以及如何正确地更新 state
,帮助开发者更好地理解和运用这一核心特性。
目录
前言
1.1 state及其特点
1.2 state的定义和使用
1.2.1 es6的类 - 构造函数
1.2.2 es7的类 - 属性初始化器
1.3 如何正确的修改state
1.4 this.setState()方法及其特点
1.4.1 传递函数
1.4.2 传递对象
总结
1.1 state及其特点
State 与 props 类似,但是 state 是私有的,并且完全受控于当前组件
不要直接修改state:构造函数是唯一可以给 this.state
赋值的地方。
state更新可能是异步的:出于性能考虑,React 可能会把多个 setState()
调用合并成一个调用。
state更新会被合并:当你调用 setState()
的时候,React 会把你提供的对象合并到当前的 state
1.2 state的定义和使用
目前react中的状态有两种使用方式:
1.2.1 es6的类 - 构造函数
src/index.js
import React from 'react'
import ReactDOM from 'react-dom/client'
// 引入时,后缀名可以省略,可以在webpack中配置
// import App from './01-App-parent-child'
// import App from './02-App-parent-child-value'
// import App from './03-App-parent-child-value-default'
// import App from './04-App-parent-child-value-default-type'
// import App from './05-App-props-children'
// import App from './06-App-mutiple-props-children'
// import App from './07-App-mouse-tracker'
// import App from './08-App-render-props'
import App from './09-App-state-es6'
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(<App />)
src/09-App-state-es6.jsx
import React, { Component } from 'react';
/*** ES6 规定,子类必须在constructor()方法中调用super(),否则就会报错。
这是因为子类自己的this对象,必须先通过父类的构造函数完成塑造,
得到与父类同样的实例属性和方法,然后再对其进行加工,添加子类自己的实例属性和方法。
如果不调用super()方法,子类就得不到自己的this对象。
ES5 的继承机制,是先创造一个独立的子类的实例对象,然后再将父类的方法添加到这个对象上面,即“实例在前,继承在后”。ES6 的继承机制,则是先将父类的属性和方法,加到一个空的对象上面,然后再将该对象作为子类的实例,即“继承在前,实例在后”*/
class App extends Component {// es6的类 - 构造函数constructor (props) {super(props) // 调用父类的constructor(props)this.state = { // 添加子类自己的实例属性和方法,在react中 state作为初始化状态的属性date: new Date()}}render() {return (<div>现在的时间是:{ this.state.date.toLocaleDateString() + this.state.date.toLocaleTimeString() }</div>);}
}
export default App;
1.2.2 es7的类 - 属性初始化器
src/index.js
import React from 'react'
import ReactDOM from 'react-dom/client'
// 引入时,后缀名可以省略,可以在webpack中配置
// import App from './01-App-parent-child'
// import App from './02-App-parent-child-value'
// import App from './03-App-parent-child-value-default'
// import App from './04-App-parent-child-value-default-type'
// import App from './05-App-props-children'
// import App from './06-App-mutiple-props-children'
// import App from './07-App-mouse-tracker'
// import App from './08-App-render-props'
// import App from './09-App-state-es6'
import App from './10-App-state-es7'
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(<App />)
src/10-App-state-es7.jsx
import React, { Component } from 'react';
// 推荐写法
class App extends Component {state = { // es7 类的属性date: new Date()}render() {return (<div>现在的时间是:{ this.state.date.toLocaleDateString() + this.state.date.toLocaleTimeString() }!!!</div>);}
}
export default App;
1.3 如何正确的修改state
setState()
将对组件 state 的更改排入队列,并通知 React 需要使用更新后的 state 重新渲染此组件及其子组件。这是用于更新用户界面以响应事件处理器和处理服务器数据的主要方式.
将 setState()
视为请求而不是立即更新组件的命令。为了更好的感知性能,React 会延迟调用它,然后通过一次传递更新多个组件。
setState()
并不总是立即更新组件。它会批量推迟更新。这使得在调用 setState()
后立即读取 this.state
成为了隐患。为了消除隐患,请使用 componentDidUpdate
或者 setState
的回调函数(setState(updater, callback)
),这两种方式都可以保证在应用更新后触发。
记住修改状态的三大原则:
-
不要直接修改 State
state = { a: 10 }
this.state.a = 100 // ❌
-
state 的更新可能是异步的
state = { a: 10 }
this.setState({a: this.state.a + 1 })
this.setState({a: this.state.a + 1 })
this.setState({a: this.state.a + 1 })
console.log(this.state.a) // 10
-
state 的更新会被合并
1.4 this.setState()方法及其特点
setState()
会对一个组件的 state
对象安排一次更新。当 state 改变了,该组件就会重新渲染。
setState()
可以添加两个参数,
setState()
的第二个参数为可选的回调函数,它将在 setState
完成合并并重新渲染组件后执行
1.4.1 传递函数
参数一为带有形式参数的 updater
函数:
this.setState((state, props) => stateChange[, callback] )
src/index.js
import React from 'react'
import ReactDOM from 'react-dom/client'
// 引入时,后缀名可以省略,可以在webpack中配置
// import App from './01-App-parent-child'
// import App from './02-App-parent-child-value'
// import App from './03-App-parent-child-value-default'
// import App from './04-App-parent-child-value-default-type'
// import App from './05-App-props-children'
// import App from './06-App-mutiple-props-children'
// import App from './07-App-mouse-tracker'
// import App from './08-App-render-props'
// import App from './09-App-state-es6'
// import App from './10-App-state-es7'
import App from './11-App-setState-function'
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(<App />)
src/11-App-setState-function.jsx
import React, { Component } from 'react';
class App extends Component {state = {count: 100}render() {return (<div>{ this.state.count }<button onClick={ () => {this.setState((state, props) => {console.log(state, props)return {count: state.count + 1}})this.setState((state, props) => {console.log(state, props)return {count: state.count + 1}})this.setState((state, props) => {console.log(state, props)return {count: state.count + 1}})} }>加</button></div>);}
}
export default App
updater 函数中接收的
state
和props
都保证为最新。updater 的返回值会与state
进行浅合并。
1.4.2 传递对象
src/index.js
import React from 'react'
import ReactDOM from 'react-dom/client'
// 引入时,后缀名可以省略,可以在webpack中配置
// import App from './01-App-parent-child'
// import App from './02-App-parent-child-value'
// import App from './03-App-parent-child-value-default'
// import App from './04-App-parent-child-value-default-type'
// import App from './05-App-props-children'
// import App from './06-App-mutiple-props-children'
// import App from './07-App-mouse-tracker'
// import App from './08-App-render-props'
// import App from './09-App-state-es6'
// import App from './10-App-state-es7'
// import App from './11-App-setState-function'
import App from './12-App-setState-object'
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(<App />)
src/12-App-setState-object.jsx
import React, { Component } from 'react';
// 为什么?
// const obj = { a: 100 }
// es6 中对象合并
// const newObj = Object.assign(obj, {a: 100 + 1}, {a: 100 + 1}, {a: 100 + 1})
// console.log(newObj) // { a: 101 }
class App extends Component {state = {count: 10}render() {return (<div>{ this.state.count }<button onClick={ () => {this.setState({count: this.state.count + 1})this.setState({count: this.state.count + 1})this.setState({count: this.state.count + 1})console.log(this.state.count)} }>加</button></div>);}
}
export default App;
这种形式的
setState()
是异步的,并且在同一周期内会对多个setState
进行批处理,相当于Object.assign( prevState, {count: this.state.count + 1}, {count: this.state.count + 1}, ... )后调用的
setState()
将覆盖同一周期内先调用setState
的值,因此商品数仅增加一次。如果后续状态取决于当前状态,建议使用 updater 函数的形式代替(前面案例已经实现)。或者在第二个参数中再继续操作。
src/index.js
import React from 'react'
import ReactDOM from 'react-dom/client'
// 引入时,后缀名可以省略,可以在webpack中配置
// import App from './01-App-parent-child'
// import App from './02-App-parent-child-value'
// import App from './03-App-parent-child-value-default'
// import App from './04-App-parent-child-value-default-type'
// import App from './05-App-props-children'
// import App from './06-App-mutiple-props-children'
// import App from './07-App-mouse-tracker'
// import App from './08-App-render-props'
// import App from './09-App-state-es6'
// import App from './10-App-state-es7'
// import App from './11-App-setState-function'
// import App from './12-App-setState-object'
import App from './13-App-setState-callback'
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(<App />)
src/13-App-setState-callback.jsx
import React, { Component } from 'react';
class App extends Component {state = {count: 10}render() {return (<div>{ this.state.count }<button onClick={ () => {this.setState({count: this.state.count + 1}, () => {this.setState({count: this.state.count + 1}, () => {this.setState({count: this.state.count + 1})})})console.log(this.state.count) // 10} }>加</button></div>);}
}
export default App;
思考题:
1.何时以及为什么 setState() 会批量执行?
2.为什么不直接更新 this.state?
总结
通过本文的介绍,我们了解了 state
在 React 组件中的重要性,以及如何在 ES6 和 ES7 类组件中定义和使用 state
。同时,我们还探讨了正确更新 state
的方法,包括使用 setState()
方法时需要注意的事项。遵循这些最佳实践,可以帮助我们避免常见的陷阱,提高应用的性能和可靠性。
相关文章:

React 组件中 State 的定义、使用及正确更新方式
🌈个人主页:前端青山 🔥系列专栏:React篇 🔖人终将被年少不可得之物困其一生 依旧青山,本期给大家带来React篇专栏内容React 组件中 State 的定义、使用及正确更新方式 前言 在 React 应用开发中,state …...

Jenkins 的HTTP Request 插件为什么不能配置Basic认证了
本篇遇到的问题 还是因为Jenkins需要及其所在的OS需要升级,升级策略是在一台新服务器上安装和配置最新版本的Jenkins, 当前的最新版本是: 2.479.2 LTS。 如果需要这个版本的话可以在官方站点下载,也可以到如下地址下载࿱…...
8 Bellman Ford算法SPFA
图论 —— 最短路 —— Bellman-Ford 算法与 SPFA_通信网理论基础 分别使用bellman-ford算法和dijkstra算法的应用-CSDN博客 图解Bellman-Ford计算过程以及正确性证明 - 知乎 (zhihu.com) 语雀版本 1 概念 **适用场景:**单源点,可以有负边࿰…...

nginx不允许静态文件被post请求显示405 not allowed
在单独站点的配置文件中 添加error_page 405 200 $request_uri; 即可!...
【c++笔试强训】(第三十二篇)
目录 数组变换(贪⼼位运算) 题目解析 讲解算法原理 编写代码 装箱问题(动态规划-01背包) 题目解析 讲解算法原理 编写代码 数组变换(贪⼼位运算) 题目解析 1.题目链接:数组变换__牛客网…...

shell脚本实战案例
文章目录 实战第一坑功能说明脚本实现 实战第一坑 实战第一坑:在Windows系统写了一个脚本,比如上面,随后上传到服务,执行会报错 原因: 解决方案:在linux系统touch文件,并通过vim添加内容&…...

OpenCV-图像阈值
简单阈值法 此方法是直截了当的。如果像素值大于阈值,则会被赋为一个值(可能为白色),否则会赋为另一个值(可能为黑色)。使用的函数是 cv.threshold。第一个参数是源图像,它应该是灰度图像。第二…...
lvgl9 Line(lv_line) 控件使用指南
文章目录 前言主体1. **Line 控件概述**2. **使用场景**3. **控件的样式**4. **设置点**5. **自动大小**6. **y 坐标反转**7. **事件处理**8. **示例代码** 总结 前言 在图形界面设计中,直线绘制是非常常见且重要的功能之一,尤其是在需要进行图形表示、…...
区块链概念 Web 3.0 实操
1. Web 3.0 概述 1.1 定义与背景 Web 3.0,也称为第三代互联网,是一个新兴的概念,它代表着互联网的未来发展和演进方向。Web 3.0的核心理念是去中心化、用户主权和智能化。这一概念的提出,旨在解决Web 2.0时代中用户数据隐私泄露…...

【人工智能】大数据平台技术及应用
文章目录 前言一、大数据平台基本概念及发展趋势1、数据量爆发式增长,发数据蓬勃发展2、大数据到底是什么?3、大数据处理与传统数据处理的差异4、为什么要建立大数据平台?5、大数据平台开源架构-Hadoop6、华为云大数据平台架构 二、大数据技术…...
Scala的模式匹配(7)
package hfdobject Test35 {case class Person(name:String)case class Student(name:String,className:String)//match case 能根据 类名和属性的信息,匹配到对应的类//注意://1 匹配的时候,case class的属性个数要对上//2 数学名不需要一一…...

使用 MATLAB 绘制三维散点图:根据坐标和距离映射点的颜色和大小
在数据可视化中,三维散点图是一种非常直观的方式来展示数据的分布。MATLAB 提供了强大的 scatter3 函数,可以用来绘制三维散点图,而通过调整点的颜色和大小,可以进一步增强图形的表现力。 在本篇博客中,我们将逐步讲解…...

数仓技术hive与oracle对比(五)
附录说明 附录是对测试过程中涉及到的一些操作进行记录和解析。 oracle清除缓存 alter system flush shared_pool; 将使library cache和data dictionary cache以前保存的sql执行计划全部清空,但不会清空共享sql区或者共享pl/sql区里面缓存的最近被执行的条目。刷…...
金融数学在股市交易中的具体应用
### 1. 风险管理 - **VaR(在险价值)**: VaR是衡量投资组合潜在损失的指标。例如,如果一个投资组合的VaR为100万元,置信水平为95%,这意味着在未来的一个交易日内,有95%的可能性该投资组合的损失不会超过100…...

Spring6:1 概述
Spring6:1 概述 标签 JAVASpring 目录 Spring 是什么?Spring 的狭义和广义 广义的 Spring:Spring 技术栈狭义的 Spring:Spring Framework Spring Framework 特点Spring 模块组成Spring6 特点 版本要求本课程软件版本 1. 概述 …...

Python Selenium 各浏览器驱动下载与配置使用(详细流程)
1、安装 pip install selenium 2、浏览器驱动下载 Chrome(google)浏览器驱动 下载地址:http://chromedriver.storage.googleapis.com/index.html 或 https://sites.google.com/a/chromium.org/chromedriver/home . 下载地址:http://chromedriver.stor…...

C语言期末考试——重点考点
目录 1.C语言的结构 2.三种循环结构 3.逻辑真假判断 4. printf函数 5. 强制类型转化 6. 多分支选择结构 7. 标识符的定义 8. 三目运算符 1.C语言的结构 选择结构、顺序结构、循环结构 2.三种循环结构 for、while、do-while 3.逻辑真假判断 C语言用0表示false,用非0(不…...

mongo开启慢日志及常用命令行操作、数据备份
mongo开启慢日志及常用命令行操作、数据备份 1.常用命令行操作2.mongo备份3.通过命令临时开启慢日志记录4.通过修改配置开启慢日志记录 1.常用命令行操作 连接命令行 格式:mongo -u用户名 -p密码 --host 主机地址 --port 端口号 库名; 如:连…...

Mybatis-Plus的主要API
一、实体类操作相关API BaseMapper<T>接口 功能:这是 MyBatis - Plus 为每个实体类对应的 Mapper 接口提供的基础接口。它提供了一系列基本的 CRUD(增删改查)操作方法。例如insert(T entity)方法用于插入一条记录,d…...

2023 年“泰迪杯”数据分析技能赛B 题企业财务数据分析与造假识别
2023 年“泰迪杯”数据分析技能赛B 题企业财务数据分析与造假识别 一、背景 财务数据是指企业经营活动和财务结果的数据记录,反映了企业的财务状况 与经营成果。对行业、企业的财务数据进行分析,就是要评价其过去的经营业绩、 衡量现在的财务状况、预测…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...
条件运算符
C中的三目运算符(也称条件运算符,英文:ternary operator)是一种简洁的条件选择语句,语法如下: 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true,则整个表达式的结果为“表达式1”…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...
《C++ 模板》
目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板,就像一个模具,里面可以将不同类型的材料做成一个形状,其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式:templa…...
【JavaSE】多线程基础学习笔记
多线程基础 -线程相关概念 程序(Program) 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存…...

C# 表达式和运算符(求值顺序)
求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如,已知表达式3*52,依照子表达式的求值顺序,有两种可能的结果,如图9-3所示。 如果乘法先执行,结果是17。如果5…...
4. TypeScript 类型推断与类型组合
一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式,自动确定它们的类型。 这一特性减少了显式类型注解的需要,在保持类型安全的同时简化了代码。通过分析上下文和初始值,TypeSc…...
Git常用命令完全指南:从入门到精通
Git常用命令完全指南:从入门到精通 一、基础配置命令 1. 用户信息配置 # 设置全局用户名 git config --global user.name "你的名字"# 设置全局邮箱 git config --global user.email "你的邮箱example.com"# 查看所有配置 git config --list…...