你理解的setState异步是对的吗?

简介: 你理解的setState异步是对的吗?

前言

在刚接触React时,我们开发用的最多的hook之一就是useState,使用它的返回值setState去更新数据时,就会发现,在有些情况下,数据并不是像预期中更新了,获取到的数据还是旧的数据。这就是为什么说setState是异步的。

但是这里初学者就有疑问了,怎么异步编程范畴里没有提到setState呢?你理解的异步真的是对的吗?

经历了React各个版本的更新,setState异步机制有什么变化呢?

入门篇

setState的使用

大家都知道setState接受一个参数,这个参数是newState值。这里再补充一些其它知识。

setState其实可以接收两个参数:

import React, { useState } from 'react';
const [state, setState] = useState(initState);
setState(newState, callback);
复制代码
  1. newState:最新值
  2. callback:异步更新之后的回调函数,即会在state更新之后执行

Tips: useState接收的initState是初始值,只会在mount时生效一次

为什么 setState 设计为异步?

import React, { useState } from 'react';
const [state, setState] = useState(false);
const changeState = ()=>{
    setState(true);
    console.log(state);   // 此处打印结果显示是:false,而不是true,表明这里setState是异步的
}
复制代码

针对这个问题,Dan在github上给出了回答:why is setState asynchronous?

这里给出总结:

  1. 保持一致性。如果同步更新了setState,但还未执行render函数,那么state和props无法保持一致性,从而引发很多问题。
  2. 批量更新,提升性能。

如果获取到setState异步更新之后的值?

1.利用setState第二个参数,callback

// setState第二个参数是一个回调函数,会在state更新后执行
this.setState({ massage: "你好" }, () => {
  console.log(this.state.message);
});
复制代码

2.componentDidUpdate 生命周期函数

进阶篇

异步的定义

在入门篇提到,setState是异步的,但这个异步不同于EventLoop里说的异步。

我们常说的Promise.then()、setTimeout是异步执行,然而setState从js执行上来说它是同步执行的。这里setState的异步是指调用setState之后state能否立即更新(即表现出来是异步的,本质是同步的)。

简而言之:setState是同步执行,异步更新

setState一定是异步的吗?

先说结论:

legacy模式下:在原生DOM事件和异步代码中,setState是同步的;在组件生命周期和React合成事件里,setState是异步的

concurrent模式下:都是异步

legacy 模式concurrent 模式傻傻分不清楚

legacy 模式是目前的主流模式,如今React18正式版已经发布,也就是说concurrent(并发)模式已经不再处于试验中,concurrent(并发)模式正式启用。

ReactDOM.render(<App />, rootNode)   // 通过这个方式创建应用,为 legacy 模式
复制代码
ReactDOM.unstable_createRoot(rootNode).render(<App />)   // 通过这个方式创建应用,为 concurrent 模式
复制代码

基于legacy模式

在React的setState函数实现中,会根据一个变量isBatchingUpdates判断是直接更新this.state还是放到队列中回头再说,而isBatchingUpdates默认是false,也就表示setState会同步更新this.state,但是,有一个函数batchedUpdates,这个函数会把isBatchingUpdates修改为true,而当React在调用事件处理函数之前就会调用这个batchedUpdates,造成的后果,就是由React控制的事件处理过程setState不会同步更新this.state**。

基于concurrent模式

React18正式版已经发布,concurrent(并发)模式正式启用。在这个模式下,setState都是异步的。

相关链接:

React 中 setState 什么时候是同步的,什么时候是异步的?



相关文章
|
3月前
|
前端开发
async和await 优雅处理异步
async和await 优雅处理异步
|
22天前
|
前端开发 JavaScript
Vue 中 Promise 的then方法异步使用及async/await 异步使用总结
Vue 中 Promise 的then方法异步使用及async/await 异步使用总结
29 1
|
9月前
|
前端开发 JavaScript
React 中 setState 什么时候是同步的,什么时候是异步的
React 中 setState 什么时候是同步的,什么时候是异步的
88 0
|
3月前
setState 和 replaceState 的区别
setState 和 replaceState 的区别
27 2
|
11月前
|
前端开发 JavaScript
react的setState是异步还是同步
react的setState是异步还是同步
|
3月前
|
监控 前端开发 JavaScript
等一下!深入async/await的异步世界
等一下!深入async/await的异步世界
64 1
|
3月前
|
JavaScript 前端开发
揭秘 `nextTick`:解决异步回调的利器(上)
揭秘 `nextTick`:解决异步回调的利器(上)
揭秘 `nextTick`:解决异步回调的利器(上)
|
3月前
|
JavaScript 前端开发
揭秘 `nextTick`:解决异步回调的利器(下)
揭秘 `nextTick`:解决异步回调的利器(下)
揭秘 `nextTick`:解决异步回调的利器(下)
|
3月前
|
缓存 Java Spring
@EventPublisher + @Async 异步事件流详解
本文主要介绍Spring事件流和`@Async`异步线程池处理,以及`@Async`默认线程池可能会导致的问题及解决方法。 在@Async注解中value参数使用自定义线程池,能让开发工程师更加明确线程池的运行规则,选取适合的线程策略,规避资源耗尽的风险
|
8月前
|
前端开发
setState异步问题
setState异步问题
48 0