在 instantiateReactComponent 模块中,我们根据 Element的不同来选择不同的方法来处理element为挂载实例,其中当Element为Object的时候,Element.type分为string,number,除此之外的为一种情况也就是type为function的时候。
一般Element.type为function指的是我们自定义的组件。 比如 的type 为 f APP(props)是一个函数。
这种情况下才有如下的方式来处理。
instance = new ReactCompositeComponentWrapper();
ReactCompositeComponentWrapper
ReactCompositeComponentWrapper 是一个构造函数,assign方法则为该构造函数添加了原型属性。 这里着重说一下 { _instantiateReactComponent: instantiateReactComponent } 为构造函数加入了 原型方法 instantiateReactComponent,自定义的组件终究是要转换为HTMl组件才能被浏览器认识,而一个自定义的组件终究是由HTML组件组成的。 这个方法赋值给构造方法的原型,则是用来递归使用 instantiateReactComponent的。 具体如何使用,往下看。
var ReactCompositeComponentWrapper = function () {};
assign(
ReactCompositeComponentWrapper.prototype, ReactCompositeComponent.Mixin,
{
_instantiateReactComponent: instantiateReactComponent
}
);
这里往 ReactCompositeComponentWrapper 构造函数添加的原型属性的主要内容是 ReactCompositeComponent。接下来先看看ReactCompositeComponent
ReactCompositeComponent.Mixin
与前边的文章
在结构上是相似的,都会拥有自己的 mountComponent ,unmountComponent,updateComponent 等方法,但是,不同的element也会有属于自己的独特方法。我们先来看看Element 为Object:type为function的时候的组件(也就是自定义组件)的挂载实例长什么样子。

如上图所示,一个APP组件的样子。
以下是 ReactCompositeComponentMixin 所暴露出来的方法,相比之下,自定义组件初始化挂载实例多了些方法。 接下来我们一个个的来看看这些方法。
var ReactCompositeComponentMixin = {
construct:function(){},
mountComponent: function (rootID, transaction, context) {},
unmountComponent: function () {},
receiveComponent: function (nextElement, transaction, nextContext) {},
performUpdateIfNecessary: function (transaction) {},
updateComponent: function (transaction, prevParentElement, nextParentElement, prevUnmaskedContext, nextUnmaskedContext) {},
attachRef: function (ref, component) {},
detachRef: function (ref) {},
getName: function () {},
getPublicInstance: function () {},
}
construct
该方法的作用是初始化一些属性,这些属性的作用不同:
在 ReactUpdateQueue 模块使用的属性:
this._pendingElement = null;
this._pendingStateQueue = null;
this._pendingReplaceState = false;
this._pendingForceUpdate = false;
this._renderedComponent = null;
this._context = null;
this._mountOrder = 0;
this._topLevelWrapper = null;
在 ReactUpdates and ReactUpdateQueue. 中使用的属性
this._pendingCallbacks = null;
mountComponent 1
mountComponent 与之前的挂载实例类型一样,主要的作用便是生成 markup。
我们知道,markup就是html标签的string表示,但是,一个自定义的组件浏览器是不认的,这里就要将其转换为 html标签的string表示。
mountComponent: function (rootID, transaction, context) {
'
为construct 方法初始化的部分属性赋值。
nextMountID初始值为1,以此递增。
'
this._context = context;
this._mountOrder = nextMountID++;
this._rootNodeID = rootID;
'
_processProps就是在 当前环境不是production的时候,校验了一下props的类型是否合规。该方法的核心作用只是返回element的 props
'
var publicProps = this._processProps(this._currentElement.props);
'
同样的的得到 context
'
var publicContext = this._processContext(context);
'
这里拿到 自定义组件的type,这个type肯定是函数,比如 ƒ App(props) 上边的图中所示
'
var Component = this._currentElement.type;
'
定义两个变量。
'
var inst;
var renderedElement;
'
判断 Component(elemen.type是一个函数)是否有 prototype属性。
'
var canInstantiate = ('prototype' in Component);
if (canInstantiate) {
。。。
'
省略多余代码,核心是下边的代码,
element.type是一个构造函数的情况,这里是new type
的一个实例。
type是一个函数,或者是type本身就是指代的组件,也就是我们自定义的组件,这个组件是继承自ReactCompnent。我们使用 es5的写法的话就是 函数的形式,es6的形式就是类了。
简单的来说,inst 就是自定义的组件的 实例。看图一与图二。
'
inst = new Component(publicProps, publicContext, ReactUpdateQueue);
。。。
}
}
图一: 定义了一个App组件。

图二: 图一的组件,生成的inst则是:
浅色的是 继承自ReactComponent的属性,深色的是定义组件的时候定义的属性。

图三: App组件的Element.type的源码表示

mountComponent 2
mountComponent: function (rootID, transaction, context) {
'
紧接mountComponent 1
如果canInstantiate为false,或者是inst为null,false,或者是inst为一个element,就执行下边的操作。
生成 StatelessComponent 实例。
这里要看一下下边的 说明 ReactElement.isValidElement:
如下边所叙述的,在无状态箭头函数组件下,inst是一个Element。renderedElement 也就是一个Element了。
而后,inst为new一个 StatelessComponent的实例。
'
if (!canInstantiate || inst === null || inst === false || ReactElement.isValidElement(inst)) {
renderedElement = inst;
inst = new StatelessComponent(Component);
}
'
为 inst 添加 属性,这里比较重要的是 updater。
比如在 ReactComponent中的setState方法使用了。
'
inst.props = publicProps;
inst.context = publicContext;
inst.refs = emptyObject;
inst.updater = ReactUpdateQueue;
'
将inst 存储在 _instance 属性里。
'
this._instance = inst;
'
存储 实例与组件element的对应。
也就是在 实例 inst上添加属性 _reactInternalInstance,且值为 当前的element对象。
'
ReactInstanceMap.set(inst, this);
}
ReactElement.isValidElement
这个方法主要是用来判断给定的对象是合法的 Element。 核心源码如下:
ReactElement.isValidElement = function (object) {
return typeof object === 'object' && object !== null && object.$$typeof === REACT_ELEMENT_TYPE;
};
REACT_ELEMENT_TYPE 是React为内部的 Element提供的一个标识,这个方法的另外一个作用是检测给定的对象是不是一个 Element。
这里说回inst。我们知道inst是Element.type new出来的一个实例。这个实例一般是如上边图一图二所示的那样,当然有一种特例。
Stateless Arrow function Component
如下所示,我们定义了一个无状态箭头函数组件。
import React from "react";
const Stateless = () => <div>Hello </div>;
export default Stateless;
它的 Element.type如下,而一个App组件则如上图三所示。
ƒ Stateless() {
return _react2.default.createElement(
"div",
null,
"Hello "
);
}
如此,我们new 一个 Element.type的实例如下:
图四:

如图所示,这个inst本身是一个 Element。
StatelessComponent
function StatelessComponent(Component) {}
StatelessComponent.prototype.render = function () {
var Component = ReactInstanceMap.get(this)._currentElement.type;
return Component(this.props, this.context, this.updater);
};
如上所示的StatelessComponent构造函数只是在原型对象上添加了render方法,别的什么也没做,而new出来的 StatelessComponent的属性则是在后续的代码中加入的。如下所示
inst.props = publicProps;
inst.context = publicContext;
inst.refs = emptyObject;
inst.updater = ReactUpdateQueue;
ReactInstanceMap.set
set: function (key, value) {
key._reactInternalInstance = value;
}
mountComponent 3
mountComponent: function (rootID, transaction, context) {
'
initialState 是 自定义的组件的 state
'
var initialState = inst.state;
'
如果自定义的组件中没有state,就将其初始化为null。initialState也置为null
'
if (initialState === undefined) {
inst.state = initialState = null;
}
'
为 _pendingStateQueue 赋值 null
_pendingReplaceState和 _pendingForceUpdate 值保持不变。
'
this._pendingStateQueue = null;
this._pendingReplaceState = false;
this._pendingForceUpdate = false;
'
生命周期componentWillMount开始执行。
'
if (inst.componentWillMount) {
inst.componentWillMount();
'
当在挂载的时候, 在方法 componentWillMount 中 调用setState 方法,
将会重设this._pendingStateQueue的值, , 而不会触发重新渲染。
关于 _pendingStateQueue请看下边的。
'
if (this._pendingStateQueue) {
'
如果_pendingStateQueue有值。调用 _processPendingState 方法来处理state,综合处理之后最终得到一个最后的state。
'
inst.state = this._processPendingState(inst.props, inst.context);
}
}
'
如果组件不是无状态组件,我们现在渲染。
在上边我们说过,在无状态箭头函数组件的情况下,这个 renderedElement是有值的。而且值为一个Element。而在其他情况下,renderedElement的值为 undefined。
这里的具体解析请往下看。
'
if (renderedElement === undefined) {
renderedElement = this._renderValidatedComponent();------(1)
}
'
首先这里 renderedElement 是一个Element。
接下来,我们再将 这个 Element 再次调用 方法 _instantiateReactComponent 来初始化挂载实例,而后赋值给 this._renderedComponent属性。
也就是一个自定义组件在初始化挂载实例(instantiateReactComponent方法)之后,会再次将其初始化挂载实例(instantiateReactComponent)。因为自定义组件浏览器是不认的。
'
this._renderedComponent = this._instantiateReactComponent(renderedElement);
'
调用 ReactReconciler.mountComponent 方法生成 markup。
至于 该方法具体是如何执行的往下看。
'
var markup = ReactReconciler.mountComponent(this._renderedComponent, rootID, transaction, this._processChildContext(context));
if (inst.componentDidMount) {
transaction.getReactMountReady().enqueue(inst.componentDidMount, inst);
}
return markup;
}
_pendingStateQueue
_pendingStateQueue 属性是自定义组件初始化的挂载实例的一个属性,默认值是null。顾名思义,这个属性的作用是记录正在等待的 state队列,也就是我们如果一次性的操作了很多次的state,那么这里state就会形成一个 Queue,而后调用 _processPendingState 方法来处理。
也就是我们说的 setstate 的批处理。 我们来看一下_pendingStateQueue属性是在哪里发生改变的。
核心是在ReactComponent 模块的setState方法中。
'
updater 依据上文,我们可以知道它是 ReactUpdateQueue。
'
this.updater.enqueueSetState(this, partialState);
看一下 ReactUpdateQueue.enqueueSetState
'
拿到 _pendingStateQueue,并为其加入新元素。
所以 _pendingStateQueue 就有了值。
'
var queue = internalInstance._pendingStateQueue || (internalInstance._pendingStateQueue = []);
queue.push(partialState);
_processPendingState
_processPendingState: function (props, context) {
var inst = this._instance;
'
转存一下 _pendingStateQueue的值。_pendingStateQueue 简单的来说就等待更新的state 暂时存在的地方。
'
var queue = this._pendingStateQueue;
var replace = this._pendingReplaceState;
this._pendingReplaceState = false;
this._pendingStateQueue = null;
'
如果不存在 queue 直接返回 inst的 state,也就是组件实例的 state。
'
if (!queue) {
return inst.state;
}
if (replace && queue.length === 1) {
return queue[0];
}
var nextState = assign({}, replace ? queue[0] : inst.state);
for (var i = replace ? 1 : 0; i < queue.length; i++) {
var partial = queue[i];
assign(nextState, typeof partial === 'function' ? partial.call(inst, nextState, props, context) : partial);
}
'
这里就是叠加的一个过程,如果一个state已经存在了,后续的同名属性会覆盖前边的,直到最后一个为止。这也就是为什么有时候我们更改了n多次的state,最终反映在页面上只会有最后一次的变动。
'
return nextState;
},
renderedElement-----(1)
if (renderedElement === undefined) {
renderedElement = this._renderValidatedComponent();------(1)
}
首先我们得来先确认一下这个this是什么鬼。
我们知道,当前的模块是,在自定义组件的实例化挂载组件的,也就是一个构造函数,那么this当然是指向构造函数的实例了。
按照图一的例子,一个App组件,经过该构造函数构造的实例如下图五所示:
图五:

简单的来说,其实就是为实例加载了很多的方法,私有的(方法名以下划线开头的)和对外暴露的方法(比如mountComponent方法)。
而_renderValidatedComponent则是实例方法之一。
_renderValidatedComponent
_renderValidatedComponent: function () {
var renderedComponent;
'
简单的记录一下当前正在构建的组件
'
ReactCurrentOwner.current = this;
try {
renderedComponent = this._renderValidatedComponentWithoutOwnerOrContext();
} finally {
ReactCurrentOwner.current = null;
}
return renderedComponent;
},
_renderValidatedComponentWithoutOwnerOrContext
_renderValidatedComponentWithoutOwnerOrContext: function () {
'
_instance属性里记录了当前组件实例的inst,而一个inst就是一个Element.type方法的构造实例。
'
var inst = this._instance;
'
调用inst的render方法。也就是我们在组件中定义的render方法。render方法会一般会返回一个 Element,这里之所以说一般是因为有其他的情况,下边render有链 接,之前的文章有写,这个Element里包含了render方法里的jsx。
比如图一的App组件的renderedComponent如下图 ,图六所示。
'
var renderedComponent = inst.render();
return renderedComponent;
},
renderedComponent

render
不同的组件render是不同的。简单的来说有三种render。参考文章这里就不再赘述了。
ReactReconciler.mountComponent
mountComponent: function (internalInstance, rootID, transaction, context) {
'
这里又调用了 internalInstance 的 mountComponent 方法。
internalInstance就是自定义组件初始化的挂载实例,这里相当于是递归了。一个自定义的组件终究是要实例化为一个 ReactDOMComponent或者是ReactTextComponent。
'
var markup = internalInstance.mountComponent(rootID, transaction, context);
if (internalInstance._currentElement && internalInstance._currentElement.ref != null) {
transaction.getReactMountReady().enqueue(attachRefs, internalInstance);
}
'
总之,到了最后,mountComponent方法生成了一个 markup。
markup就是组件的html的表示方法
比如:
<div data-reactid=".0">
<span data-reactid=".0.0">this is app </span>
<span data-reactid=".0.1">13</span>
<div data-reactid=".0.2">Hello </div>
</div>
'
return markup;
},