愚墨的博客
  • 首页
  • 前端技术
  • 面试
只争朝夕不负韶华
  1. 首页
  2. 前端框架
  3. React
  4. 正文

如何理解setState是同步还是异步

2020年05月14日 3352点热度 1人点赞 0条评论

本篇文章只是为了回答徒弟@河北小女孩 的一个问题,setState 是同步的还是异步的?

翻阅了一下react-dom的源码外加上自己的经验,总结出以下两点:

  • 同步代码下异步执行
  • 异步代码下同步执行

同步代码下异步执行

在非事件回调和setTimeout下,比如react的生命周期中,setState 的代码是异步执行的。

constructor() {
    super();
    this.state = {
      val: 0,
    };
  }
  componentDidMount() {
    console.log(this.state.val, '1'); // 0
    this.setState({
      val: this.state.val + 1,
    });
     this.setState({
      val: this.state.val + 1,
    });
    console.log(this.state.val, '2'); // 0
    console.log(this.state.val, '3'); // 0
  }
  componentDidUpdate() {
    console.log('did');
    console.log(this.state.val);
  }

原因是:react源码中有一个 isBatchingUpdates: false,在每个事务开始前会被置为 true,事务结束后的close会被再置回false;

isBatchingUpdates 为 true,所以并不会直接执行更新 state,而是加入了 dirtyComponents,,等待后续执行,所以此时会被异步挂起。所以打印时获取的都是更新前的状态 0。

还有一个重点,多个异步的setState 会被合并执行,所以componentDidUpdate 只会被执行一次,且是 1。

异步代码同步执行

如果你的setState是被setTimeout包裹的,或者是事件函数中的回调fn,那setState就会被同步的执行。且不会被合并执行,会导致组件被渲染多次。

  componentDidMount() {
    setTimeout(() => {
      console.log(this.state.val, '1');
      this.setState({
        val: this.state.val + 1,
      });
      this.setState({
        val: this.state.val + 1,
      });
      console.log(this.state.val, '2');
      console.log(this.state.val, '3');
    }, 0);
  }
  componentDidUpdate() {
    console.log('did');
    console.log(this.state.val);
  }

所以执行结果就是

0 "1"
did
1
did
2
2 "did"
2 "did"

setState 同步执行,且每次都会重新render组件。

源码解释 因为 回调函数异步执行 已经是在事务close之后了,这个时候 isBatchingUpdates 已经是false 了,所以会直接更新。所以就是同步执行。

记住了么@河北小女孩 ?

标签: 暂无
最后更新:2020年10月11日

愚墨

保持饥渴的专注,追求最佳的品质

点赞
< 上一篇
下一篇 >

文章评论

取消回复

搜搜看看
历史遗迹
  • 2023年5月
  • 2022年9月
  • 2022年3月
  • 2022年2月
  • 2021年12月
  • 2021年8月
  • 2021年7月
  • 2021年5月
  • 2021年4月
  • 2021年2月
  • 2021年1月
  • 2020年12月
  • 2020年11月
  • 2020年9月
  • 2020年7月
  • 2020年5月
  • 2020年4月
  • 2020年3月
  • 2020年1月
  • 2019年5月
  • 2019年3月
  • 2019年2月
  • 2019年1月
  • 2018年9月
  • 2018年3月
  • 2018年2月
  • 2018年1月
  • 2017年11月
  • 2017年7月
  • 2017年6月
  • 2017年3月
  • 2017年2月
  • 2017年1月
  • 2016年12月
  • 2016年11月
  • 2016年9月
  • 2016年8月
  • 2016年7月
  • 2016年6月
  • 2016年5月
  • 2016年4月
  • 2016年3月
  • 2016年2月
  • 2016年1月
  • 2015年12月
  • 2015年10月
  • 2015年9月
  • 2015年7月
  • 2015年6月
  • 2015年4月

COPYRIGHT © 2020 愚墨的博客. ALL RIGHTS RESERVED.

THEME KRATOS MADE BY VTROIS