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 函数中接收的 stateprops 都保证为最新。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() 方法时需要注意的事项。遵循这些最佳实践,可以帮助我们避免常见的陷阱,提高应用的性能和可靠性。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

长沙市的科技查新机构有哪些

中南大学图书馆科技查新站&#xff1a; 中南大学图书馆科技查新站成立于2003年12月&#xff0c;中南大学图书馆科技查新站作为教育部首批批准的科技查新工作站之一&#xff0c;具备了在全国范围内开展科技查新工作的专业资质。 长沙理工大学科技查新工作站&#xff1a; 长沙理…

数组 - 八皇后 - 困难

************* C topic: 面试题 08.12. 八皇后 - 力扣&#xff08;LeetCode&#xff09; ************* Good morning, gays, Fridary angin and try the hard to celebrate. Inspect the topic: This topic I can understand it in a second. And I do rethink a movie, …

IDEA的service窗口中启动类是灰色且容易消失

大家在学习Spring Cloud的过程中,随着项目的深入,会分出很多个微服务,当我们的服务数量大于等于三个的时候,IDEA会给我们的服务整理起来,类似于这样 但是当我们的微服务数量达到5个以上的时候,再启动服务的时候,服务的启动类就会变成灰色,而且还容易丢失 解决方法 我们按住…

threejs相机辅助对象cameraHelper

为指定相机创建一个辅助对象&#xff0c;显示这个相机的视锥。 想要在场景里面显示相机的视锥&#xff0c;需要创建两个相机。 举个例子&#xff0c;场景中有个相机A&#xff0c;想要显示相机A的视锥&#xff0c;那么需要一个相机B&#xff0c;把B放在A的后面&#xff0c;两个…

应用层协议/传输层协议(UDP)

目录 应用层 如何自定义应用层协议&#xff1f; 序列化方式 1.基于行文本的方式来传输 2.基于xml的方式 3.基于json的方式 4.yml的形式 5.protobuffer(pb)形式 传输层 端口号 协议 UDP 校验和 CRC TCP TCP/IP五层协议 应用层 -- 传输层 -- 网络层 -- 数据链路层…

cocotb value cocotb—基础语法对照篇

cocotb—基础语法对照篇 import cocotb from cocotb.triggers import Timer from adder_model import adder_model from cocotb.clock import Clock from cocotb.triggers import RisingEdge import randomcocotb.test() async def adder_basic_test(dut):"""Te…

【NoSQL数据库】Hbase基本操作——数据库表的增删改查

目录 一、Hbase原理 二、HBase数据库操作 三、遇到的问题和解决方法 一、Hbase原理 HBase的数据模型&#xff1a; 行键 时间戳 列族&#xff1a;contents 列族&#xff1a;anchor 列族&#xff1a;mime “com.cnn.www” T9 Achor:cnnsi.com”CNN” T8 Achor:…

【NLP高频面题 - LLM架构篇】大模型使用SwiGLU相对于ReLU有什么好处?

【NLP高频面题 - LLM架构篇】大模型使用SwiGLU相对于ReLU有什么好处&#xff1f; 重要性&#xff1a;★★★ &#x1f4af; NLP Github 项目&#xff1a; NLP 项目实践&#xff1a;fasterai/nlp-project-practice 介绍&#xff1a;该仓库围绕着 NLP 任务模型的设计、训练、优化…

ElementUI 问题清单

1、form 下面只有一个 input 时回车键刷新页面 原因是触发了表单默认的提交行为&#xff0c;给el-form 加上submit.native.prevent就行了。 <el-form inline submit.native.prevent><el-form-item label"订单号"><el-inputv-model"query.order…

AWS 机器学习,推动 AI 技术的健康发展

目录 一、AI 正在改变生产方式二、从炒作走向务实1、选对场景2、重视数据3、产品思维4、持续优化 三、人才是最稀缺的资源四、负责任的 AI 开发五、未来已来六、启示与思考七、结语 如果说传统软件开发是手工作坊&#xff0c;那么 AI 就像工业革命带来的机器生产。 在最新的一…

【第 1 章 初识 C 语言】1.8 使用 C 语言的 7 个步骤

目录 1.8 使用 C 语言的 7 个步骤 1.8.1 第 1 步&#xff1a;定义程序的目标 1.8.2 第 2 步&#xff1a;设计程序 1.8.3 第 3 步&#xff1a;编写代码 1.8.4 第 4 步&#xff1a;编译 1.8.5 第 5 步&#xff1a;运行程序 1.8.6 第 6 步&#xff1a;测试和调试程序 1.8.…

C++知识整理day4内存管理——new和delete详解

文章目录 1.C/C内存分布2.C语言中动态内存管理&#xff1a;malloc/realloc/calloc3.C内存管理方式3.1 new/delete操作内置类型3.2 new和delete操作自定义类型 4.malloc/free和new/delete到底什么区别&#xff1f;4.1 对于自定义类型4.2 对于自定义类型4.3 总结&#xff1a;它们…

实现跨平台 SSH 连接:从 macOS 到 Windows WSL 的完整解决方案20241203

&#x1f310; 实现跨平台 SSH 连接&#xff1a;从 macOS 到 Windows WSL 的完整解决方案 ✨ 引言 随着跨平台开发的普及&#xff0c;开发者经常需要在多系统环境中切换和协作。尤其是在 macOS 和 Windows 混合使用的开发环境中&#xff0c;通过 SSH 远程访问和管理 Windows …

检索增强生成RAG与知识图谱

检索增强生成RAG与知识图谱 一、检索增强生成&#xff08;RAG&#xff09;1、简介2、RAG 的优点3、RAG的应用场景4、RAG增强原理 二、知识图谱介绍1、简介2、知识图谱的应用场景3、优劣势分析a、优点:b、缺点: 4、应用实例5、知识图谱和图数据库的关系 一、检索增强生成&#x…

Vue前端开发-路由跳转及带参数跳转

在Vue 3中&#xff0c;由于没有实例化对象this&#xff0c;因此&#xff0c;无法通过this去访问 $route对象&#xff0c;而是通过导入一个名为 useRouter 的方法&#xff0c;执行这个方法后&#xff0c;返回一个路由对象&#xff0c;通过这个路由对象就可以获取到当前路由中的信…

第九篇:k8s 通过helm发布应用

什么是helm&#xff1f; Helm 是 Kubernetes 的包管理器。Helm 是查找、分享和使用软件构建 Kubernetes 的最优方式。 在红帽系的Linux中我们使用yum来管理RPM包&#xff0c;类似的&#xff0c;在K8s中我们可以使用helm来管理资源对象&#xff08;Deployment、Service、Ingress…

SQL——DQL分组聚合

分组聚合&#xff1a; 格式&#xff1a; select 聚合函数1(聚合的列),聚合函数2(聚合的列) from 表名 group by 标识列; ###若想方便分辨聚合后数据可在聚合函数前加上标识列&#xff08;以标识列进行分组&#xff09; 常见的聚合函数: sum(列名):求和函数 avg(列名)…

【Linux】ubuntu下一键配置vim

&#x1f525;个人主页&#x1f525;&#xff1a;孤寂大仙V &#x1f308;收录专栏&#x1f308;&#xff1a;Linux &#x1f339;往期回顾&#x1f339;&#xff1a;Linux权限&#xff08;超详细彻底搞懂Linux的权限&#xff09; &#x1f516;流水不争&#xff0c;争的是滔滔…

42_GAN网络详解(2)---常见的GAN

DCGAN CGAN 条件生成对抗网络&#xff08;Conditional Generative Adversarial Networks, CGAN&#xff09;是生成对抗网络&#xff08;Generative Adversarial Networks, GAN&#xff09;的一种变体&#xff0c;由Mehdi Mirza和Simon Osindero在2014年提出。CGAN的主要改进在…

burp常用机漏洞测试理论

声明&#xff01; 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章&#xff0c;笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以及泷羽sec团队无关&a…