React 组件中 State 的定义、使用及正确更新方式

news/2024/12/24 0:18:19/

​🌈个人主页:前端青山
🔥系列专栏: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

javascript">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

javascript">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

javascript">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

javascript">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

javascript">state = { a: 10 }
this.state.a = 100 // ❌
  • state 的更新可能是异步的

javascript">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 函数:

javascript">this.setState((state, props) => stateChange[, callback] )

src/index.js

javascript">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

javascript">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 函数中接收的 stateprops 都保证为最新。updater 的返回值会与 state 进行浅合并。

1.4.2 传递对象

src/index.js

javascript">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

javascript">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

javascript">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

javascript">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() 方法时需要注意的事项。遵循这些最佳实践,可以帮助我们避免常见的陷阱,提高应用的性能和可靠性。


http://www.ppmy.cn/news/1557590.html

相关文章

uniapp中的uni-file-picker组件上传多张图片到服务器

由于在uniapp官方文档中的uni-file-picker组件可实现图片上传功能&#xff0c;默认的是上传到自带的服务&#xff0c;所以我们要修改成自己的服务器 1. 添加 :auto-upload"false" 加上这个取消自动上传 <uni-file-picker v-model"jobAddUpdateForm.imag…

使用Node.js搭配express框架快速构建后端业务接口模块Demo

使用Node.js搭配express框架快速构建后端业务接口模块Demo&#xff01;实际开发中&#xff0c;有很多项目&#xff0c;其实都是可以使用node.js来完成对接mysql数据库的&#xff0c;express确实使用起来非常简单&#xff0c;入手快&#xff0c;效率非常高。下面是一个简单的案例…

数据可视化-4. 漏斗图

目录 1. 漏斗图适用场景分析 1.1 业务流程分析 1.2 营销活动分析 1.3 客户生命周期管理 2. 漏斗图局限性 2.1 数据量限制 2.2 信息丢失 2.3 静态展示 2.4 过于简化 2.5 转化窗口期的影响 2.6 用户细分限制 3. 漏斗图代码实现 3.1 Python 代码实现 3.2 漏斗图效果…

Unity 圆形循环复用滚动列表

一.在上一篇垂直循环复用滚动列表的基础上&#xff0c;扩展延申了圆形循环复用滚动列表。实现此效果需要导入垂直循环复用滚动列表里面的类。 1.基础类 using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using UnityEngine.EventSystems; using …

Deepin和Windows传文件(Xftp,WinSCP)

在Linux系统和Windows系统传输文件&#xff0c;通常通过Windows系统中安装的Xftp和WinSCP访问Linux系统&#xff0c;在访问前需要安装配置SSH-Server 安装SSH-Server 安装SSH-Server sudo apt-get install openssh-server ssh -v 启动SSH服务 sudo systemctl start ssh //也…

Telegram bot Mini-App开发实践---Telegram简单介绍与初始化小程序获取window.Telegram.WebApp对象并解析

➡️【好看的灵魂千篇一律,有趣的鲲志一百六七!】- 欢迎认识我~~ 作者:鲲志说 (公众号、B站同名,视频号:鲲志说996) 科技博主:极星会 星辉大使 后端研发:java、go、python、TS,前电商、现web3 主理人:COC杭州开发者社区主理人 、周周黑客松杭州主理人、 AI爱好…

react 项目打包二级目 使用BrowserRouter 解决页面刷新404 找不到路由

使用BrowserRouter package 配置 &#xff08;这部分代码可以不做配置也能实现&#xff09; {"homepage": "/admin",}vite.config 配置 export default defineConfig({base: /admin])BrowserRouter 添加配置项 <BrowserRouter basename/admin>&l…

文件包含漏洞之进阶利用

包含Apache日志文件getshell phpmyadmin文件包含 1.CVE-2018-12613 本地文件包含漏洞 参考链接&#xff1a;CVE-2018-12613 本地文件包含漏洞复现漏洞分析 下载 phpmyadmin漏洞版本&#xff0c;解压&#xff0c;重命名为 phpMyAdmin 放在本地phpstudy网站根目录。 ​ ​ 登…