React-函数setState的执行

By
写代码

setStateReact里使用频率最高的的一个操作,React的状态更新,不同于vue的直接this.data设置,需要都要通过这个函数进行。

在使用中,总结setState的3个特性:

1、异步更新,即调用setState之后立刻获取更新值,通常不会取到最新的值;
2、合并更新,例如在不同的生命周期(componentWillMountomponentDidMount等)进行的状态更新,最终只会触发一次;
3、可以传入对象或者函数。

本篇依然使用单步调试的方法,首先在之前的例子里添加state和相关的setState操作:

调用栈

1、setState函数的处理

this.setState是定义在ReactComponent原型上的方法,定义在ReactBaseClasses.js

如果定义了回调函数,那么会把回调函数也放进待处理队列enqueueCallback。

internalInstance是从实例的属性_reactInternalInstance查找到ReactCompositeComponentWrapper对象,这个对象是之前渲染的时候‘脱壳’TopLevelWrapper之后重新包装的,并通过属性建立了反向链接,位置在上一篇步骤2.3)。

ReactUpdates.enqueueUpdate函数的处理,决定了state是同步或是异步更新。

2、更新队列的处理

那么state具体是什么时候更新呢?跳回去想想,enqueueUpdate,不管是否初次渲染,最后都是放在transactionReactDefaultBatchingStrategyTransaction)里执行的,那么肯定会在最后执行releaseAll,就需要把更新放在这里。

记得ReactDefaultBatchingStrategyTransaction里定义了两个transactionWrapper吗?其中一个就是FLUSH_BATCHED_UPDATES

flushBatchedUpdates使用了另外一个Transaction:ReactUpdatesFlushTransaction

ReactUpdatesFlushTransaction结构
react-transaction-flush-transaction

ReactUpdatesFlushTransaction重写了peform,函数内部还包装了一个transaction的perform:ReactReconcileTransaction.perform,所以会有两层Transaction执行过程。

调用过程

可以看到,剥开了前面包上去的wrapper,最终执行的函数就是runBatchedUpdates

updateComponent包含各种状态和属性判断,还有生命周期函数调用:

1)判断context是否更改;
2)判断props是否更改(如更改,调用生命周期方法componentWillReceiveProps);
3)判断state更改,_processPendingState合并处理状态更改:

调用生命周期方法componentWillUpdate
更新_currentElement指向的对象,更改_instance指向的实例propsstatecontext

4)更新属性

更新props,更新DOM(DOM更新暂时不看)

5)调用生命周期方法componentDidUpdate

小记

state有可能会立即更新吗?

如果是在某次batchedUpdates的处理过程中(比如首次渲染),即batchingStrategy.isBatchingUpdatestrue,那么setState只负责把statecallback放进队列里,然后就接着执行下面的函数部分了。此时,state的更新就会不同步。

如果是setState发生的时候,并没有进行中的batchedUpdate,就会主动调用batchingStrategy.batchedUpdates方法,开始一轮新的batchedUpdates,之后的处理和上面一样,statecallBack会被放入队列,继续执行其他函数。

特殊情况,比如给setState包了timeoutinterVal、写进了异步请求处理函数中,都会使setState所在的函数,脱离了原本的React处理流程,就会造成setState每次都同步更新。

→延申阅读Why isn’t this.state updated immediately?

目前依然没涉及到实际的react节点变为HTML节点,即_mountImageIntoNode方法。

0

Comments: 0

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*

:razz: