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 个人博客 所有,欢迎分享本文,转载请保留出处,谢谢!

相关文章
|
前端开发
异步转同步的几种方法
在循环等待中,我们可以使用一个变量来指示异步操作是否已完成。然后,我们可以在循环中检查该变量,如果它指示异步操作已完成,则退出循环。
490 0
|
30天前
|
JavaScript Java Spring
@Async异步失效的9种场景
在Spring中,启用@Async异步功能需要在启动类或配置类上使用`@EnableAsync`。若未使用此注解,@Async将无效。另外,内部方法调用(如在一个类的方法中调用另一个被@Async注解的方法)会导致异步功能失效,因为这不涉及Spring的AOP代理。此外,@Async方法必须是public,返回类型为void或Future,不能是static或final,且其所在的类需被@Service等注解以使Spring管理。如果使用@ComponentScan,确保正确扫描包含@Async类的包路径。
|
1月前
|
负载均衡 算法 前端开发
同步和异步
同步和异步
52 0
|
7月前
|
前端开发 JavaScript
React 中 setState 什么时候是同步的,什么时候是异步的
React 中 setState 什么时候是同步的,什么时候是异步的
71 0
|
9月前
|
前端开发 JavaScript
react的setState是异步还是同步
react的setState是异步还是同步
|
1月前
|
存储 JavaScript 前端开发
|
1月前
|
监控 前端开发 JavaScript
async/await:使用同步的方式去写异步代码
async/await:使用同步的方式去写异步代码
62 1
|
6月前
|
前端开发
setState异步问题
setState异步问题
42 0
|
10月前
|
前端开发
react中setState是同步还是异步
react中setState是同步还是异步
84 0
|
前端开发
前端学习案例1-this.setstate是同步和异步
前端学习案例1-this.setstate是同步和异步
60 0
前端学习案例1-this.setstate是同步和异步