setState()异步 同步

简介: setState()异步 同步

上上篇博客我讲了setState() 的批处理合并,而setState()是异步的还是同步的,和setState() 的批处理有很大的关系,推荐先看完上上篇博客再来看这篇,会清晰很多

地址如下:http://biaoblog.run/#/bookInfo/1625016158478

setState()批处理

问题:setState()是异步的还是同步的?
先看异步的情况:

import React, { Component } from 'react';

class com2 extends Component {
state = {

num: 0

}

add = () => {

this.setState({
  num: this.state.num + 1
})
console.log(this.state.num)

this.setState({
  num: this.state.num + 2
})
console.log(this.state.num)

this.setState({
  num: this.state.num + 3
})
console.log(this.state.num)

}

render() {

return (
  <div>
    <button onClick={this.add}>按钮{this.state.num}</button>
  </div>
);

}
}

export default com2;
复制代码
结果如下:

å¨è¿éæå¥å¾çæè¿°

å¨è¿éæå¥å¾çæè¿°

之前说过,react内部为了优化setState()的批处理,会对setState()进行合并,并且对相同属性的设置只保留最后一次的设置,所按钮上3是可以理解的,

但是打印出三次0,那又是为啥?

在 React 的 setState 函数实现中,会根据一个变量 isBatchingUpdates 判断是直接更新 this.state 还是放到一个updateQueue中延时更新,而 isBatchingUpdates 默认是 false,表示 setState 会同步更新 this.state;但是,有一个函数 batchedUpdates,该函数会把 isBatchingUpdates 修改为 true,而当 React 在调用事件处理函数之前就会先调用这个 batchedUpdates将isBatchingUpdates修改为true,这样由 React 控制的事件处理过程 setState 不会同步更新 this.state,而是异步的。

总结:

所以说setstate本身是同步的,一旦走了react内部的合并逻辑,放入了updateQueue队列中就变成异步了,而代码中的函数是react控制的,内部会走合并逻辑,所以这里的setState 不但是合并的也是异步的,所以打印出三个0

控制setState的同步和异步:
上面说了,setState是异步的原因是因为走了react内部的合并逻辑,那只要能绕过react内部的合并逻辑,不让它进入到updateQueue中不就变成同步了吗?因为setState()本身就是同步的

利用setTimeout绕过react内部的合并逻辑

import React, { Component } from 'react';
class com2 extends Component {
state = {

num: 0

}

add = () => {

        //利用setTimeout绕过react的控制,不让setState()走合并逻辑
setTimeout(() => {
  this.setState({
    num: this.state.num + 1
  })
  console.log(this.state.num)

  this.setState({
    num: this.state.num + 2
  })
  console.log(this.state.num)

  this.setState({
    num: this.state.num + 3
  })
  console.log(this.state.num)
});

}

render() {

return (
  <div>
    <button onClick={this.add}>按钮{this.state.num}</button>
  </div>
);

}
}

export default com2;
复制代码
结果如下:

å¨è¿éæå¥å¾çæè¿°

å¨è¿éæå¥å¾çæè¿°

总结:

异步的情况:

由React控制的事件处理函数,以及生命周期函数调用setState时表现为异步 。大部分开发中用到的都是React封装的事件,比如onChange、onClick、onTouchMove等(合成事件中),这些事件处理函数中的setState都是异步处理的。

同步的情况:

React控制之外的事件中调用setState是同步更新的。比如原生js绑定的事件,setTimeout/setInterval,ajax,promise.then内等 React 无法掌控的 APIs情况下,setState是同步更新state的,

值得一提的是

setState()可以接收一个对象外,还可以接收一个函数:

区别:
传递对象

批处理,对相同变量进行的多次处理会合并为一个,并以最后一次的处理结果为准

传递函数

链式调用,React 会把我们更新 state 的函数加入到一个队列里面,然后,按照函数的顺序依次调用。同时,为每个函数传入 state 的前一个状态,这样,就能更合理的来更新我们的 state 了,该函数有两个参数

prevState

props

这和我们前面理解的setState()异步执行不冲突

可以理解为:

本来我想拿到上一次setState() 执行完后的结果,需要使用一些特殊的方式,绕开合并逻辑,让setState() 保持本身的同步执行特性,代码如下:

import React, { Component } from 'react';

class com2 extends Component {

state = {

count: 0

}

add = () => {

setTimeout(()=>{
  this.setState({
    count: this.state.count + 1
  })
  console.log(this.state.count)
  this.setState({
    count: this.state.count + 1
  })
  console.log(this.state.count)
  this.setState({
    count: this.state.count + 1
  })
  console.log(this.state.count)
})

}

render() {

return (
  <div>
    <button onClick={this.add}>按钮{this.state.count}</button>
  </div>
);

}
}

export default com2;
复制代码
点击后结果:

å¨è¿éæå¥å¾çæè¿°

å¨è¿éæå¥å¾çæè¿°

而现在,在异步执行的情况下,我还想拿到上一次setState执行完后的结果,react给我们提供了方式,就是在setState()里面传入一个函数,代码如下:

import React, { Component } from 'react';

class com2 extends Component {

state = {

count: 0

}

add = () => {

this.setState((state) => {
  // 重要:在更新的时候读取 `state`,而不是 `this.state`。
  return { count: state.count + 1 }
});
console.log(this.state.count)
this.setState((state) => {
  // 重要:在更新的时候读取 `state`,而不是 `this.state`。
  return { count: state.count + 1 }
});
console.log(this.state.count)
this.setState((state) => {
  // 重要:在更新的时候读取 `state`,而不是 `this.state`。
  return { count: state.count + 1 }
});
console.log(this.state.count)

}

render() {

return (
  <div>
    <button onClick={this.add}>按钮{this.state.count}</button>
  </div>
);

}
}

export default com2;
复制代码
结果如下:

å¨è¿éæå¥å¾çæè¿°

å¨è¿éæå¥å¾çæè¿°

在setState中传一个函数,能拿到上次setState执行完后的结果,但是不妨碍是异步更新的,可以看到打印的是0,这是react给我们提供的方便之处

转载:https://blog.csdn.net/fesfsefgs/article/details/108036605

作者: Bill 本文地址: http://biaoblog.cn/info?id=1625017790526

版权声明: 本文为原创文章,版权归 biaoblog 个人博客 所有,欢迎分享本文,转载请保留出处,谢谢!

相关文章
|
人工智能 自然语言处理 机器人
谷歌AI Gemin怎么使用?Gemini国内使用指南!(2024.8.19)
从自然语言处理(NLP)到对话生成,AI语言模型已经成为科技界的一个重要组成部分。在众多杰出的AI语言模型中,Gemini凭借其卓越的性能和广泛的应用而脱颖而出。作为谷歌旗下的多模态AI巨头,Gemini融合了最先进的语言处理技术,为用户提供了无与伦比的语言理解和生成能力。
|
消息中间件 存储 缓存
消息队列(六)
消息队列(六)
349 0
消息队列(六)
|
区块链
区块链研习 | 详解三大主要跨链技术,如何推动价值网络的实现
2017年以来,区块链项目井喷状出现。截至2017年底,GitHub上的项目数超过8万,另据coinmarketcap数据显示,目前已有token种类达到150
4819 0
|
5天前
|
云安全 人工智能 自然语言处理
|
9天前
|
人工智能 Java API
Java 正式进入 Agentic AI 时代:Spring AI Alibaba 1.1 发布背后的技术演进
Spring AI Alibaba 1.1 正式发布,提供极简方式构建企业级AI智能体。基于ReactAgent核心,支持多智能体协作、上下文工程与生产级管控,助力开发者快速打造可靠、可扩展的智能应用。
849 26
|
3天前
|
机器学习/深度学习 人工智能 自然语言处理
Z-Image:冲击体验上限的下一代图像生成模型
通义实验室推出全新文生图模型Z-Image,以6B参数实现“快、稳、轻、准”突破。Turbo版本仅需8步亚秒级生成,支持16GB显存设备,中英双语理解与文字渲染尤为出色,真实感和美学表现媲美国际顶尖模型,被誉为“最值得关注的开源生图模型之一”。
435 4
|
12天前
|
数据采集 人工智能 自然语言处理
Meta SAM3开源:让图像分割,听懂你的话
Meta发布并开源SAM 3,首个支持文本或视觉提示的统一图像视频分割模型,可精准分割“红色条纹伞”等开放词汇概念,覆盖400万独特概念,性能达人类水平75%–80%,推动视觉分割新突破。
822 59
Meta SAM3开源:让图像分割,听懂你的话