React用了有一段时间了,抽空写分析一下setState。
卧槽,刚要写词穷了。
关于react组件挂载、刷新、卸载都执行了那些,流程的概念如果不清楚请看
好啦进入正题,在react入门中我们经常接触到的就是createClass \ render\getInitialState等一下相关方法和生命周期的方法。为了让数据灵活性的变更,组件内部变化让组件变成一个活组件,我们用到了setState,用起来挺爽,改什么setState一下,ok啦,要是追本溯源setState干了啥,那些地方set了会被合并set,那些是reRender呢?
嗯本宝宝要开始吹牛逼了。
先上个图
/** * Mark a component as needing a rerender, adding an optional callback to a * list of functions which will be executed once the rerender occurs. */function enqueueUpdate(component) { ensureInjected(); // Various parts of our code (such as ReactCompositeComponent's // _renderValidatedComponent) assume that calls to render aren't nested; // verify that that's the case. (This is called by each top-level update // function, like setProps, setState, forceUpdate, etc.; creation and // destruction of top-level components is guarded in ReactMount.) if (!batchingStrategy.isBatchingUpdates) { batchingStrategy.batchedUpdates(enqueueUpdate, component); return; } dirtyComponents.push(component);}
简单说来,React 内部有一个ReactDefaultBatchingStrategy文件,这个家伙主要管的就是更新State的,它在React实例化的时候就被注入到ReactUpdates的类,它很傲娇,每次更新state的时候都会将isBatchingUpdates锁定。这个时候如果有setState到来的时候全部放入dirtyComponents队列里,等待锁定状态解除了将所有存储的state状态设定拿出来进行合并,然后render,反之如果isBatchingUpdates没有被锁定则直接render。
说了一段大白话,敢举个例子说一下嘛?
例子来了,网上都会拿这个例子来说
看一下这个setState在那里设置,componentDidMount,原来是组件挂载完成啊。
直观理解1、2、3、4哈哈那就错了。上边有提到傲娇的isBatchingUpdates了吧。先看看componentDidMount的时候它的状态。
为毛才说,好吧我们开始一段state(以下简称BU)的诡(jie)异(ke)之旅,当然setState就是state的代(lao)言(ma)人(zi),来看看那里state我们的傲娇妹纸会接受呢(奸笑脸能不能set的幕后推手isBatchingUpdates)?
getDefaultProps 对于一个组件只初始化一次的大叔来说,state还没出生呢,不接。
getInitialState 这里也是set不了,妹纸内心OS:不要脸,人家刚刚初始化,你就你就要set一下,滚。(but state的初始化值就来自于这里)
componentWillMount 啦啦啦 我是除了init那家伙(给定初始值)以外第一个可以调用setState的人(yin),这是setState时isBatchingUpdates还是false耶,所以state会合并一次render到DOM(看这里,只render一次哦),然后isBatchingUpdates被锁定了。
render 上边的一堆都是啥,最后我才是state的接盘侠,这里如果有条件的setState,由于isBatchingUpdates已经处于锁定状态,所以set的值会放入等待队列,然后ComponentDidMount调用结束后reRender。
componentDidMount 我来了,卧槽前面有个妹纸(state),but她不喜欢我,willMount追了她,我反复的追她,她不理我,
因为isBatchingUpdates还在锁定中,
好消息是我成了state妹纸的备胎(放入等待队列),坏消息是我走了以后妹纸的资源才会被释(fen)放(shou),一个不好不坏的消息,等我从备胎变成了千斤顶,最终还是交给了render。
好了说说说上边的例子执行流程和结果。
第一次setState 由于状态锁定中,所以val被放入待更新队列,第二次也是一样
然后componentDidMount执行完毕,锁定状态解除,妹纸单身啦。然后他们两个setState作为一次合并在一起,然后更新state,这个时候state变成了1.(reRender)
第三次 setState 这时候锁定状态已经解除,来者不拒,所以第三次reRender
第四次依旧是reRender