setState是异步还是同步?

在介绍这个问题之前,我们先来看一下一个例子:

js

state = {number:1};componentDidMount(){this.setState({number:3})console.log(this.state.number)}

看完这个例子,也许很多小伙伴会下意识的以为setState是一个异步方法,但是其实setState并没有异步的说法,之所以会有一种异步方法的表现形式,归根结底还是因为react框架本身的性能机制所导致的。因为每次调用setState都会触发更新,异步操作是为了提高性能,将多个状态合并一起更新,减少re-render调用。

试想一下如果在组件中有以下这样一段代码执行:

js

for(leti =0; i <100; i++ ) {this.setState( {num:this.state.num+1} );}

如果setState是一个同步执行的机制,那么这个组件会被重新渲染100次,这对性能是一个相当大的消耗。

显然,React也是想到了这个问题,因此对setState做了一些特殊的优化:

React会将多个setState的调用合并为一个来执行,也就是说,当执行setState的时候,state中的数据并不会马上更新

这也很好的印证了刚才提到的那个例子。我们可以看下面代码会在控制台上打印什么?

但是往往在实际的开发工作中,我们可能需要同步的获取到更新之后的数据,那么怎么获取呢?下面介绍几种常用的方法:

回调函数

setState提供了一个回调函数供开发者使用,在回调函数中,我们可以实时的获取到更新之后的数据。还是以刚才的例子做示范:

js

state = {number:1};componentDidMount(){this.setState({number:3},()=>{console.log(this.state.number)    })}

这个时候大家可以看到控制台打印的数据就是最新的了,我们也就实时的获取到了最新的数据。

setTimeout

上面我们讲到了,setState本身并不是一个异步方法,其之所以会表现出一种异步的形式,是因为react框架本身的一个性能优化机制。那么基于这一点,如果我们能够越过react的机制,是不是就可以令setState以同步的形式体现了呢?

说再多文字不如代码实践,实践才是检验真理的唯一标准,下面我们还是以之前的例子为基础改造一下代码:

js

state = {number:1};componentDidMount(){setTimeout(()=>{this.setState({number:3})console.log(this.state.number)},0)}

patek-sz.jshdwatch.com

patek-fzs.jshdwatch.com

patek-hzs.xajshd.com

patek-njs.xajshd.com

patek-bjs.nnjshd.com

patek-shs.nnjshd.com

patek-sz.hebjshd.com

patek-wzs.hebjshd.com

patek-gzs.watchrft.cn

patek-shenzhen.watchrft.cn

patekw.shrhzb.com

patekw.jshdvip.com

patekw.watchsha.cn

patekw.watch-hdl.com

patekw.ruifengshi.com

patekw.watchrft.cn

patekw.watchhls.com

patekw.csjshd.com

patekw.jshdzg.com

patekw.jshdsx.com

patekw.watchwx8.com

patekw.watchwx5.com

patekw.watchjwh.cn

patekw.watchjwd.cn

patekw.shjshd.cn

patekw.rogerweixiu.com

patekw.zhcxb.cn

patekw.aysza.cn

patekw.hx626.com

patekw.ernestshwx.com

patek-cds.kpkwatch.com

patek-hzs.kpkwatch.com

patek-njs.hntwx.cn

patek-sys.hntwx.cn

patek-bjs.biaoshouhou.cn

patek-gzs.buchererweixiu.com

patek-bjs.hidcwatch.com

patek-gzs.watchgz.cn

patek-bjs.hntwx.cn

patek-gzs.aysza.cn

patek-bjs.watchjwf.cn

patek-gzs.zzjshd.com

patek-bjs.shmwatch.cn

patek-gzs.watch-service.com.cn

patek-bjs.zhcxb.cn

patek-bjs.jshdvip.com

patek-zzs.iwatch4s.com

patek-gzs.jhpwd.cn

patek-bjs.wzjshd.com

patek-zzs.jws-watch.com

原生事件中修改状态

上面已经印证了避过react的机制,可以同步获取到更新之后的数据,那么除了setTimeout以外,还有在原生事件中也是可以的。还是看一下例子:

javascript

state = {number:1};componentDidMount() {document.body.addEventListener('click',this.changeVal,false);}changeVal =() =>{this.setState({number:3    })console.log(this.state.number)}

总结

setState本身并不是异步,只是因为react的性能优化机制体现为异步。在react的生命周期函数或者作用域下为异步,在原生的环境下为同步。

1.setState 只在合成事件和钩子函数中是“异步”的,在原生事件和 setTimeout 中都是同步的。

2.setState的“异步”并不是说内部由异步代码实现,其实本身执行的过程和代码都是同步的,只是合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值,形式了所谓的“异步”,当然可以通过第二个参数 setState(partialState, callback) 中的callback拿到更新后的结果。

3.setState 的批量更新优化也是建立在“异步”(合成事件、钩子函数)之上的,在原生事件和setTimeout 中不会批量更新,在“异步”中如果对同一个值进行多次 setState , setState 的批量更新策略会对其进行覆盖,取最后一次的执行,如果是同时 setState 多个不同的值,在更新时会对其进行合并批量更新。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容