有惊无险地看完了setState
源码的精彩内容,正打算整理一下激动的情绪,梳理一下逻辑,记下读后感,然后就在React功夫网发现了同样介绍setState的文章,感觉作者的思路很清晰,所以就打算在参考它的基础上把这篇文章给撸完。
go go go ...
首先得先找到入口,在ReactClass.createClass
声明构造函数的代码中Constructor.prototype = new ReactClassComponent();
,可以看出构造函数的原型继承自ReactClassComponent
,而ReactClassComponent
的源码如下:
var ReactClassComponent = function() {};
Object.assign(
ReactClassComponent.prototype,
ReactComponent.prototype,
ReactClassMixin
);
ReactClassComponent
的原型又合并了ReactComponent
的原型,所以构造函数Constructor
的原型也就有了ReactComponent.prototype
的setState
的方法。
SO,我们看一下ReactComponent.prototype.setState
的方法实现吧。
首先看下这个方法的注释
Sets a subset of the state. Always use this to mutate
state. You should treatthis.state
as immutable.
There is no guarantee that
this.state
will be immediately updated, so
accessingthis.state
after calling this method may return the old value.
There is no guarantee that calls to
setState
will run synchronously,
as they may eventually be batched together. You can provide an optional
callback that will be executed when the call to setState is actually
completed.
When a function is provided to setState, it will be called at some point in the future (not synchronously). It will be called with the up to date component arguments (state, props, context). These values can be different from this.because your function may be called after receiveProps but before shouldComponentUpdate, and this new state, props, and context will not yet be assigned to this.
提取一下上面的大概中心思想:
- 通过
setState
去更新this.state
,不要直接操作this.state
,请把它当成不可变的。 - 调用
setState
更新this.state
不是马上生效的,它是异步滴,所以不要天真以为执行完setState
后this.state
就是最新的值了。 - 多个顺序执行的
setState
不是同步地一个一个执行滴,会一个一个加入队列,然后最后一起执行,即批处理
那,有了个大概认识,就开始深入探险吧,Let's go...
ReactComponent.prototype.setState = function(partialState, callback) {
...
this.updater.enqueueSetState(this, partialState);
if (callback) {
this.updater.enqueueCallback(this, callback, 'setState');
}
};
-
setState
被加入updater的队列来执行它的工作。 -
callback
也被加入updater的队列,如果存在的话。
别急,接下来你会明白为什么的。
那updater
是什么呢?这个名称意味着它会与更新组件有关。先来看看它在哪里定义吧。在ReactClass.createClass
和ReactComponent
的构造函数中,可以看到
this.updater = updater || ReactNoopUpdateQueue;
React的源码中大量应用依赖注入原理,这使得React.js可以优雅地实现在不同平台下(服务器端,浏览器端,手机端等)的渲染。ReactComponent
脚本存在于isomorphic
目录 - 意味着它支持异构,即它可用于React Native,在浏览器端或服务器端运行的ReactDOM
那,真实的updater在哪里被注入的呢?那就得知道ReactComponent
Class在哪里被New,经过千山万水,终于在ReactCompositeComponent
的_constructComponentWithoutOwner
方法中找到
_constructComponentWithoutOwner: function(publicProps, publicContext) {
var Component = this._currentElement.type;
var instanceOrElement;
if (shouldConstruct(Component)) {
...
instanceOrElement = new Component(publicProps, publicContext, ReactUpdateQueue);
...
} else {
...
}
return instanceOrElement;
},
可以看出updater
是ReactUpdateQueue
,这就真的找到了吗?其实不然,我们顺着往上找,经过_constructComponent
,最终定位到mountComponent
,从这句代码inst.updater = ReactUpdateQueue;
可以看出最终的updater
,还是ReactUpdateQueue
,哈哈,虽然没变,但最终决定updater
的值确实就是这里。
OK,知道了这个updater
的真面目,那~,我们先休息一下吧,在下章节我们再来深入了解enqueueSetState
和enqueueCallback
是怎么工作的吧。
最后,期待吐槽,期待指教!!!
--EOF--