开始使用react已经有快一年的时间了,但是对其背后的原理也好 实现也好,依然没有很清晰的概念,基本就是照搬前人的代码和使用方法了。
问题背景是这样的,之前 有写到 一个弹窗,在setState的时候将弹窗的visible设置为true,之后在回调里 通过 refs来获得这个弹窗元素,想象中是这样的,然而真的 实现起来发现这样是有问题的,log出来的弹窗dom元素是undefind?这说明 setState成功后,回调里并没有立即渲染?interesting。。。接着 我去了解了一下 setState相关的东西。
first,setState真的是异步么
答案是否定的,setState的同步异步取决于不同的调用场景。结论可以先说,在经过react包装的一些环境里,setState确实是异步执行的,而在未经过react包装比如settimeout&&原生事件里setState是同步的。我们可以大胆猜测,默认的情况下,setState是同步的,而在react里调用环境里,通过改变了一些数据,使得setState变成同步执行。
setState通常的运用场景:
1. 在生命周期里使用,其中一般运用较多的为componentDidMount,在这里setState以异步的方式执行。
2. 在react包装过的合成事件中执行setState,执行异步。
3.settimeout里调用setState,setState同步执行。
4.原生事件中,即用 addEventListener或者是document.querySelector().onclick的方式,在这些事件回掉里使用setState也会同步执行。
上文说到,react有一些magic操作来决定了要不要异步执行,首先,要明确的是,setState异步执行指的到底是什么,我们通常遇到的setState是batch操作,即当有一个setState被执行时,内部会创建一个待更新的队列。每一次setState都是往队列里推入新的东西。而在原生事件或者settimeout里,setState是立即执行,并不再是批量更新了。(恍然大悟哦,所以异步指的就是batch操作,并不是真正的异步!!)官方文档是这样介绍的:
将 nextState 浅合并到当前 state。这是在事件处理函数和服务器请求回调函数中触发 UI 更新的主要方法。不保证 setState 调用会同步执行,考虑到性能问题,可能会对多次调用作批处理。
setState被触发后,直接被塞到队列里等待更新还是 直接执行更新 取决于一个参数,isBatchingUpdates,默认的这个参数为false即不进行batch更新,在react合成事件和生命周期函数里会调用一个batchedUpdates 函数 ,将isBatchingUpdates修改为true。而在一些未经react包装过的事件处理中,因为状态值为false,就直接走了立即更新的操作。
然而 搞了半天 最初的困惑还是没有解决。。。。。。算了 再开一篇吧