React中setState/useState的使用

news/2025/1/17 7:54:31/

一、React如何使用setState/useState的最新的值

一般是可以正常的把最新的值,传递给所需要的函数中的,但是有些情况,需要使用最新数据的函数,不可改动,甚至所需要使用的地方并不是一个函数,那我们如何获取setState/useState的最新的值呢?

A.使用setState的最新的值
1、setState方法可以接收两个参数,第一个参数为一个对象,第二个参数为一个函数,即更新成功后执行的回调函数。我们可以在回调函数中获取更新后的值。

import React, { Component } from 'react'export default class DemoClassComp extends Component {constructor(props) {super(props)this.state = {number: 1,}}inControl = ()=>{this.setState({number: 1}, () => {console.log('%c 📯 DemoClassComp -> inControl -> this.state.number ', 'font-size:16px;background-color:#f31440;color:white;', this.state.number)})}render() {return (<div><button onClick={this.inControl} >点我</button></div>)}
}

2、使用setTimeout

B.使用useState的最新的值
1、使用另一个Hook,useRef;

function DemoFuncComp() {const [qimingFlag, setQimingFlag] = useState(false);const qimingFlagRef = useRef(false);const handleLine = () => {deleteQimingFieldsData(data, qimingFlagRef?.current); //* 删除启明相关字段的数据}const initData = useCallback(async () => {await commonQuery(basicInfoHeader, { contractId });const qimingFlagNow = basicInfoHeader.current?.get('qimingFlag');setQimingFlag(qimingFlagNow); //* 用于出发重新渲染qimingFlagRef.current = qimingFlagNow;handleLine(); //* 要求 先setQimingFlag}, [contractId])/**生命周期 */useEffect(() => {initData();}, [contractId]);return (<><Form dataSet={basicInfoHeader} disabled={true} columns={4}><Lov name="receiverObj" /></Form></>)
}

2、使用setTimeout

二、React中setState/useState执行的同步异步问题

只要代码进入了 react调度流程,那就是异步的。
只要代码没有进入 react调度流程,那就是同步的。
setTimeout、setInterval、async中await的后续部分,Promise.then(),以及直接在 DOM 上绑定原生事件等。这些都不会走 React调度流程,在这种情况下调用 setState ,那这次 setState 就是同步的。 否则就是异步的。

连续执行两个 useState

function DemoFuncComp() {const [a, setA] = useState(0);const [b, setB] = useState(0);console.log('render')function outControl() {Promise.resolve().then(() => {setA((a) => a + 1);setB((b) => b + 1);})}function inControl() {setA((a) => a + 1);setB((b) => b + 1);}return (<><button onClick={outControl} >{a}-{b} 【不受react调度】</button><button onClick={inControl} >{a}-{b} 【react调度】</button></>)
}
//! 当点击【不受react调度】按钮时,render 了两次
//! 当点击【react调度】按钮时,只重新 render 了一次

连续执行两次同一个 useState

function DemoFuncComp() {const [a, setA] = useState(1)console.log('a', a)function outControl() {Promise.resolve().then(() => {setA((a) => a + 1)setA((a) => a + 1)})}function inControl() {setA((a) => a + 1)setA((a) => a + 1)}return (<><button onClick={outControl} >{a} 【不受react调度】</button><button onClick={inControl} >{a} 【react调度】</button></>)
}//! 当点击【不受react调度】按钮时,两次 setA 各自 render 一次,分别打印 2,3
//! 当点击【react调度】按钮时,两次 setA 都执行,但合并 render 了一次,打印 3

连续执行两个 setState

class DemoClassComp extends React.Component {constructor(props) {super(props)this.state = {a: 1,b: 'b',}}outControl = () => {Promise.resolve().then(() => {this.setState({...this.state, a: 'aa'})this.setState({...this.state, b: 'bb'})})}inControl = () => {this.setState({...this.state, a: 'aa'})this.setState({...this.state, b: 'bb'})}render() {console.log('render')return (<><button onClick={this.outControl} >【不受react调度】</button><button onClick={this.inControl} >【react调度】</button></>)}
}//! 当点击【不受react调度】按钮时,render 了两次
//! 当点击【react调度】按钮时,只重新 render 了一次

连续执行两次同一个 setState

class DemoClassComp extends React.Component {constructor(props) {super(props)this.state = {a: 1,}}outControl = () => {Promise.resolve().then(() => {this.setState({a: this.state.a + 1})this.setState({a: this.state.a + 1})})}inControl = () => {this.setState({a: this.state.a + 1})this.setState({a: this.state.a + 1})}render() {console.log('a', this.state.a)return (<><button onClick={this.outControl} >【不受react调度】</button><button onClick={this.inControl} >【react调度】</button></>)}
}//! 当点击【不受react调度】按钮时,两次 setState 各自 render 一次,分别打印 2,3
//! 当点击【react调度】按钮时,两次 setState 合并,只执行了最后一次,打印 2

总结
在正常的react调度流程中时:

  • setState和useState都是异步执行的
  • 多次执行setState和useState,会进行一次batchUpdate,只会重新渲染render一次
  • 不同的是,多次执行,setState会进行state的合并,而useState每次运行都会重新计算
    不再react调度流程中时:
  • setState和useState是同步执行的(立即更新state,触发render,然后继续执行)
  • 多次执行setState和useState,每一次的执行setState和useState,都会调用一次render

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

相关文章

《Effective Objective-C 2.0 》 阅读笔记 item8

第8条&#xff1a;理解“对象等同性”这一概念 1. 对象等同性 “”操作比较的是两个指针本身&#xff0c;而不是其所指的对象。 应该使用NSObject协议中声明的“isEqual:”方法来判断两个对象的等同性。其中&#xff0c;某些对象提供了特殊的“等同性判定方法”&#xff0c;如…

网易二面:MongoDB索引底层使用的是什么数据结构?

文章目录 mongoDB存储引擎对B-tree 的误解开始B 树的单条记录查询性能真的好于 B+ 树吗?B+ 树的优势为mongoDB存储引擎 mongoDB使用的存储引擎有: 1、WiredTiger存储引擎是mongodb3.2的默认存储引擎; 2、MMAPv1是mongodb基于内存映射最初的存储引擎; 3、In-Memory是一种…

【分布式】java实现分布式事务的五种方案

文章目录背景什么是分布式事务什么是分布式系统&#xff1a;什么是事务&#xff1a;什么是本地事务&#xff1a;什么是分布式事务&#xff1a;分布式事务有哪些应用场景&#xff1a;如何进行分布式事务控制CAP理论分布式系统如何兼顾CAP&#xff1f;CAP有哪些组合方式&#xff…

todo-list遇到的问题

vue事件修饰符 .stop event.stopPropagation() .prevent event.preventDefault()mysql默认字符集是 latin&#xff0c;&#xff0c;在插入中文的时候会报错, # docker中编辑mysql配置文件# docker进入容器docker exec -it mymysql /bin/bash # 安装vim yum update yum …

C++ - 继承 | 菱形继承

之前的文章中我们简要的讲述了C中继承部分的知识&#xff0c;但是还没有完全的讲完&#xff0c;在本文中将会讲到菱形继承的问题。 复杂的菱形继承 单继承&#xff1a;一个子类只有一个直接父类时称这个继承关系为单继承。 多继承&#xff1a;一个子类有两个或以上直接父类时…

函数设计—参数规则

【规则1-1】参数的书写要完整&#xff0c;不要贪图省事只写参数的类型而省略参数名字。 如果函数没有参数&#xff0c;则用 void 填充。 例如&#xff1a; void SetValue(int width, int height); // 良好的风格 void SetValue(int, int); // 不良的风格 float GetValue(…

Android 9.0系统源码_窗口管理(三)WindowManagerService对窗口的管理过程

前言 上一篇我们具体分析了WindowManager的addView方法添加窗口的过程&#xff0c;我们知道WindowManager最终会调用到WindowManagerService的addWindow方法。本篇文章我们将在此基础上&#xff0c;具体来分析WindowManagerService的addWindow方法添加窗口的过程。这个方法的代…

selenium和Firefox的安装配置

selenium和firefox的安装配置1.1、Firefox的安装1.2、Firefox驱动geckodriver的安装1.3、geckodriver环境配置两种方式1.3.1、直接添加1.3.2、手动配置1.4、python安装selenium库两种方式1.4.1、使用pip命令进行安装1.4.2、Pycharm当中安装1.1、Firefox的安装 这之前我们先安装…