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 题企业财务数据分析与造假识别 一、背景 财务数据是指企业经营活动和财务结果的数据记录,反映了企业的财务状况 与经营成果。对行业、企业的财务数据进行分析,就是要评价其过去的经营业绩、 衡量现在的财务状况、预测…...

【SpringMVC】参数传递 重定向与转发 REST风格
文章目录 参数传递重定向与转发REST风格 参数传递 ModelAndView:包含视图信息和模型数据信息 public ModelAndView index1(){// 返回页面ModelAndView modelAndView new ModelAndView("视图名");// 或// ModelAndView modelAndView new ModelAndView(…...

性能测试需求分析(超详细总结)
🍅 点击文末小卡片 ,免费获取软件测试全套资料,资料在手,涨薪更快 1、客户方提出 客户方能提出明确的性能需求,说明对方很重视性能测试,这样的企业一般是金融、电信、银行、医疗器械等;他们…...

显卡(Graphics Processing Unit,GPU)架构详细解读
显卡架构主要分为两大类:GPU 核心架构(也称为图形处理单元架构)和显卡的其他组件(如内存、控制器、输出接口等)。本篇文章将对显卡架构进行详细分析,重点介绍 GPU 核心架构、显卡计算单元、显存结构、显卡管…...

【大语言模型】ACL2024论文-24 图像化歧义:Winograd Schema 挑战的视觉转变
【大语言模型】ACL2024论文-24 图像化歧义:Winograd Schema 挑战的视觉转变 目录 文章目录 【大语言模型】ACL2024论文-24 图像化歧义:Winograd Schema 挑战的视觉转变目录摘要研究背景问题与挑战如何解决核心创新点算法模型实验效果(包含重要…...

AcWing 2868. 子串分值
文章目录 前言代码思路 前言 还是实力不允许啊,要是实力允许我就一道一道中等题刷了。简单题真够呛。有些题看题解都是看老半天看不懂,假设是这种我是真感觉没必要钻研。我现在大三,要是看一遍题解看不懂就算了,果断放弃。真可以…...

如何进行 JavaScript 性能优化?
要进行 JavaScript 性能优化,我们可以从多个角度进行思考,主要包括减少页面渲染时间、减少内存占用、优化代码执行效率等。以下是优化的一些方法,并结合实际项目代码示例讲解。 目录结构 减少 DOM 操作 缓存 DOM 元素批量更新 DOM 优化 Jav…...

使用TCP编程实现简单登录功能
在Java中,使用TCP编程实现登录功能通常涉及以下步骤: 创建服务器端,监听特定端口,等待客户端连接。创建客户端,连接到服务器端。客户端发送用户名和密码到服务器端。服务器端验证用户名和密码。服务器端返回验证结果给…...

卷积神经网络(CNN)的层次结构
卷积神经网络(CNN)是一种以其处理图像和视频数据的能力而闻名的深度学习模型,其基本结构通常包括以下几个层次,每个层次都有其特定的功能和作用: 1. 输入层(Input Layer): 卷积神经网…...

操作系统文件管理相关习题2
文件管理的任务和功能文件管理 任务:对用户文件和系统文件进行组织管理,以方便用户使用,并保证文件的安全 功能:文件存储空间的管理,目录管理,文件读写管理和保护 目录管理 对目录管理的要求 实现按名存…...

react 通过ref调用子组件的方法
背景 父组件内引入了一个弹窗组件,弹窗组件使用了完全内聚的开发方法; 实现思路 父组件内通过ref获取的子组件,通过current调用子组件的方法,子组件需要通过forwardRef进行“包装”导出,通过useImperativeHandle暴露…...