【React学习】React中的setState方法

1. setState概述

setState 是React框架中,用于更新组件状态的方法。
setState 方法由React组件继承自 React.Component 类的一部分。通过调用 setState,可以告诉 React要更新组件的状态,并触发组件的重新渲染。

this.setState(newState, callback);

newState 是一个对象,它包含了需要更新的状态属性和值。它将合并到组件的当前状态中。
callback 是一个回调函数,它在 setState 更新状态完成之后被调用。

2. setState为何使用不可变值

  • 什么是 不可变值

React框架中的“不可变值”的概念,通常指的是在编写React组件时,尽量避免直接修改数据,而是创建新的数据副本。

  • setState为何使用不可变值?

在React中,组件的状态(state)应该保持不变。通过使用 setState 方法更新状态时,React会合并现有状态和新状态,而不是直接修改状态。 这确保 React 可以正确地追踪状态的变化并进行必要的更新。

同时,直接修改数据可能会引发意外的副作用,尤其是在多个组件之间共享数据时。通过使用不可变值,可以减少出现这种问题的可能性。

常用的处理不可变值的工具包括 Object.assign、数组的 concatslice 等方法。对数组或者对象使用slice()方法,可以生成该数组或对象的副本,类似于深拷贝。

const list5Copy = this.state.list5.slice()
list5Copy.splice(2, 0, 'a') // 中间插入/删除this.setState({list1: this.state.list1.concat(100), // 追加list2: [...this.state.list2, 100], // 追加list3: this.state.list3.slice(0, 3), // 截取list4: this.state.list4.filter(item => item > 100), // 筛选list5: list5Copy // 其他操作
})

3. setState可能是异步的

setState是一个异步方法。这意味着React可能会对多个 setState 调用进行批处理,然后一次性更新组件的状态,而不是每次调用都立即更新。

然而,setTimeout 函数中的 setState 是同步的。在自定义的DOM事件中,setState也是同步的。

state要在构造函数中定义

constructor(props){this.state = {count: 0}
}

因为 setState 是异步的,因此在 setState 方法执行完后打印状态,是拿不到更新后的值,只能拿到当前状态的值。

this.setState({count: this.state.count + 1; 
})
console.log(this.state.count) //打印结果为 0

如果想要拿到最新的状态,需要在setState中,写一个回调函数。此时count的结果为1

this.setState({count: this.state.count + 1},() => {console.log(this.state.count)}
)
  • setTimeout 中的 setState 是同步的。此时打印出来的count结果就是1
setTimeout(()=>{this.setState({count: this.state.count + 1})console.log(this.state.count)  // 打印结果为1
}, 0)
  • 在自定义的DOM事件中,setState也是同步的。
bodyClickHandler = () => {this.setState({count: this.state.count + 1})console.log(this.state.count)   // 打印结果为1
}componentDidMount(){document.body.addEventListener('click', this.bodyClickHandler)
}

4. setState何时合并state

  • setState是异步更新的话,传入的参数是一个对象,那么多次更新同一个状态只会执行1次。
constructor(props){this.state = {count: 0}
}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) // 打印结果为 1

由于 setState 是异步的,React 会将这些更新一起批处理,然后应用它们。这意味着所有三个 setState 调用可能几乎同时执行,使用初始值 this.state.count,导致增加只有 1 而不是 3。

上述代码的思想类似于

Object.assign({count: 1}, {count: 1}, {count: 1}) // 执行结果为 {count: 1}
  • 为了防止这种情况发生,可以在setState中传入更新函数(updater function),它接受先前的状态并返回更新后的状态。这能够确保使用的是最新的状态。
constructor(props){this.state = {count: 0}
}this.setState((prevState) => ({count: prevState.count + 1
}));
this.setState((prevState) => ({count: prevState.count + 1
}));
this.setState((prevState) => ({count: prevState.count + 1
}));console.log(this.state.count) // 打印结果为 3

5. React18中的setState

  • 当React的版本小于等于17时,在组件中直接使用setState更新状态,是批处理的(即异步更新且合并相同状态)。在setTimeout方法和自定义DOM事件中,使用setState方法更新状态是同步的,不是批处理的。
  • 然而,在React18版本中,无论是在组件中直接更新状态还是在自定义DOM事件和setTiemout方法中更新,都是自动批处理(Automatic Batching)。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言中常见的一些语法概念和功能

常用代码: 程序入口:int main() 函数用于定义程序的入口点。 输出:使用 printf() 函数可以在控制台打印输出。 输入:使用 scanf() 函数可以接收用户的输入。 条件判断:使用 if-else 语句可以根据条件执行不同的代码…

【力扣每日一题】2023.8.15 字符中的查找与替换

目录 题目: 示例: 分析: 代码: 题目: 示例: 分析: 题目很长,简而言之就是检查字符串中对应索引的位置是否有特定的字符串,如果有,那么替换,返…

Ceph如何操作底层对象数据

1.基本原理介绍 1.1 ceph中的对象(object) 在Ceph存储中,一切数据最终都会以对象(Object)的形式存储在硬盘(OSD)上,每个的Object默认大小为4M。 通过rados命令,可以查看一个存储池中的所有object信息,例如…

Optional的基础运用

Optional的基础运用 简介代码示例 简介 代码示例 package org.example;import org.junit.Test;import java.util.Optional;public class OptionalTest {Testpublic void advance() {String str "hello";str null;// of(T t):封装数据t生成Optional对象&#xff0c…

【笔试题心得】关于正则的一些整理

本文部分内容摘抄整理自 正则表达式 – 教程 | 菜鸟教程 在笔试的过程中,也常常会对正则表达式进行考察,这里对正则表达式的常见用法,做一个学习和总结。 正则表达式的模式可以包括以下内容: 字面值字符:例如字母、数…

数据结构:堆的实现

1.堆的概念 如果有一个关键码的集合 K { k1 &#xff0c;k2 &#xff0c;k3 &#xff0c;…&#xff0c;kn }&#xff0c;把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中&#xff0c;并且 k(i) < k(i*21) 和 k(i) < k(i*22)&#xff0c; i 0 &#xff…

MongoDB增删改查操作

数据库操作&#xff1a; 在MongoDB中&#xff0c;文档集合存在数据库中。 要选择使用的数据库&#xff0c;请在mongo shell程序中发出 use <db> 语句 // 查看有哪些数据库 show dbs;// 如果数据库不存在&#xff0c;则创建并切换到该数据库&#xff0c;存在则直接切换到…

分布式消息中间件

消息中间件是Java开发消息队列的一种中间件产品。中间件类似windows编程开发中的插件。工具插件在软件工具中是中间插件。插件也是应用程序。消息的分发过程包装之后是chatlog 系统或者是手机短信。系统与系统之间的通信通过消息的发送和接收。堆积频繁过多的系统通知消息需要进…

C++之模板进阶

模板进阶 非类型模板参数模板的特化概念函数模板特化类模板特化全特化偏特化 模板分离编译什么是分离编译模板的分离编译解决方法 模板总结 非类型模板参数 模板参数分两种&#xff1a;类型形参与非类型形参。 类型形参&#xff1a;出现在模板参数列表中&#xff0c;跟在class…

docker安装consul

1、下载consul镜像 docker pull consul2、启动consul docker run -d --restartalways --name consul -p 8500:8500 consul agent -server -bootstrap-expect1 -ui -bind0.0.0.0 -client0.0.0.03、查看consul日志 docker logs consul4、检验是否安装成功

drawio----输出pdf为图片大小无空白(图片插入论文)

自己在写论文插入图片时为了让论文图片放大不模糊&#xff0c;啥方法都试了&#xff0c;最后摸索出来这个。 自己手动画图的时候导出pdf总会出现自己的图片很小&#xff0c;pdf的白边很大如下如所示&#xff0c;插入论文的时候后虽然放大不会模糊&#xff0c;但是白边很大会显…

【数据结构OJ题】用队列实现栈

原题链接&#xff1a;https://leetcode.cn/problems/implement-stack-using-queues/ 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 可以用两个队列去实现一个栈&#xff0c;每次始终保持一个队列为空。 入栈相当于给非空队列进行入队操作。 出栈相…

异步电机IM-改进的电压模型磁链观测器学习

导读&#xff1a;本期文章主要介绍异步电机的改进型电压模型磁链观测器。传统纯积分形式的积分器在低速区域存在初始值问题和直流偏置问题&#xff0c;所以在实际应用中必须对电压模型进行改进。本期文章中的对电压模型改进是借鉴一篇IEEE中的方法。 如果需要文章中对应的仿真…

Apache Dubbo 云原生可观测性的探索与实践

作者&#xff1a;宋小生 - 平安壹钱包中间件资深工程师 Dubbo3 可观测能力速览 Apache Dubbo3 在云原生可观测性方面完成重磅升级&#xff0c;使用 Dubbo3 最新版本&#xff0c;你只需要引入 dubbo-spring-boot-observability-starter 依赖&#xff0c;微服务集群即原生具备以…

贪心算法实现找零问题

思路&#xff1a; 使用 贪心算法 的思想 题目&#xff1a; 柠檬水找零 在柠檬水摊上&#xff0c;每一杯柠檬水的售价为5美元。顾客排队购买你的产品,一次购买一杯。 每位顾客只买一杯柠檬水,然后向你付5美元、10美元或20美元。必须给每个顾客正确找零 注意,一开始你手头没有任何…

PSP - 基于扩散生成模型预测蛋白质结构 EigenFold 算法与环境配置

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/132357976 Paper: EigenFold: Generative Protein Structure Prediction with Diffusion Models EigenFold 是用于蛋白质结构预测的扩散生成模型…

使用深度学习实现的图像伪造检测: 一个Python毕业项目指南

1. 引言 在当前的数字化时代&#xff0c;图像处理和伪造技术越来越先进。从影视制作到社交媒体&#xff0c;人们常常与修饰或改变过的图片打交道。虽然这为创意产业提供了无数机会&#xff0c;但也为不诚实的内容创造者带来了伪造和篡改图像的机会。因此&#xff0c;图像伪造检…

Selenium手动和自动两种方式启动Chrome驱动

1. 自动启动chrome驱动(已经安装了Selenium库和Chrome驱动) 要使用Selenium自动跟随自带的Chrome驱动&#xff0c;你需要首先确保你已经安装了Selenium库和Chrome驱动。然后&#xff0c;你可以按照以下步骤进行操作&#xff1a; 导入必要的库&#xff1a; from selenium imp…

【面试八股文】每日一题:谈谈你对线程的理解

每日一题-Java核心-谈谈你对线程的理解【面试八股文】 Java线程是Java程序中的执行单元。一个Java程序可以同时运行多个线程&#xff0c;每个线程可以独立执行不同的任务。线程的执行是并发的&#xff0c;即多个线程可以同时执行。 1. 线程的特点 Java中的线程有如下的特点 轻…

react-native-webview使用postMessage后H5不能监听问题(iOS和安卓的兼容问题)

/* 监听rn消息 */ const eventListener nativeEvent > {//解析数据actionType、extraconst {actionType, extra} nativeEvent.data && JSON.parse(nativeEvent.data) || {} } //安卓用document&#xff0c;ios用window window.addEventListener(message, eventLis…