乐趣区

setState的异步小结

前言
关于 setState 的异步,随便一搜就是一堆文章,从各种现象到海量源码,长篇巨制洋洋洒洒,像我这样的新手看得云里雾里,晕头转向。但这个问题又无比简单,仅需理解两点浅显的道理,便能拨云见日:1. 同步代码不可能异步;2. 如果 ” 异步 ” 了,一定是执行顺序发生了改变。
1. 生命周期函数中
componentDidMount: 该方法执行完毕后才更新,state 在更新完成后(didupdate)再设置为新的值。setState 后续的代码在生命周期函数中执行,此时 state 还未变更,因此表现出 ” 异步 ” 特性。
2. 合成事件中
同理,setState 在事件中同步执行完毕,react 准备更新(will),state 在更新完成后(didupdate)再设置为新的值。setState 后续的代码在触发事件时执行,顺序在 state 变更之前。
注:state 的合并,只能将同步的 setState 合并掉,两次事件的变更无法合并, 任你点击得再快
3. 异步方法及原生事件
react 监控的只有生命周期函数和合成事件,而非 setState,在这两个方法执行前会先设置 isBatchingUpdates 为 true,导致 state 等更新完毕后再改变,因此其他情况下,batchedUpdates 为 false,setState 同步更新。同样,state 也是在更新完成后设为新的值,但是 setState 后续的代码也是在更新完成之后执行,因此表现出同步特性。
注:同理,Promise 的构造函数内的 setState,因为构造函数的同步性,当其处于 1 和 2 的情况下时,也会呈现出 ” 异步 ”
4. 结论

setState 不是变更 state 的方法,只是发送了变更的请求
无论是生命周期函数还是合成事件函数,它们都会被放入 react 的事务中,而事务的前置钩子内会修改 isBatchingUpdates 为 true
因 isBatchingUpdates 为 true,setState 会走批量更新模式,合并同样的 state,并不即时修改 state,从而使后续的同步代码在 state 变更前就执行了,表现出 ” 异步 ” 的特性
react 没有监控异步方法和原生事件,因此,即使它们声明的时候处在生命周期函数或者合成事件中,它们执行的时候,isBatchingUpdates 必定已经被事务的后置钩子设为 false 了,因此表现出同步的特性
同步时,state 的改变和后续代码的执行,都是在 did update 后,” 异步 ” 时,先即使执行了后续的代码,而后在 did update 之后执行了 state 的变更
最后的总结就是,setState 是同步的,或者是带引号的 ” 异步 ”

退出移动版