我们先来解析 _renderSubtreeIntoContainer 方法的第一部分
第一部分的核心是 生成了一个 nextWrappedElement 而关于 nextWrappedElement 参考文章 Element总结篇
简单的来说 nextWrappedElement 就是将 下边的跟元素或者叫做 container。转换为Element。
<div id="app"></div>
在生成nextWrappedElement的时候,加入了参数 nextElement,而这个nextElement就是 我们再 项目main.js或者是index.js 文件中的 下边这个代码的 ' <App/>'组件。
ReactDOM.render(<App />, document.getElementById("app"));
prevComponent 就是查看一下,当前的 根元素 id为app的div内是不是已经有组件了,也就是判断是初始化不是。
_renderSubtreeIntoContainer: function (parentComponent, nextElement, container, callback) {
var nextWrappedElement = new ReactElement(TopLevelWrapper, null, null, null, null, null, nextElement);
var prevComponent = instancesByReactRootID[getReactRootID(container)];
}
这一部分就包含了两行代码。我们一行行来看
TopLevelWrapper
var nextWrappedElement = new ReactElement(TopLevelWrapper, null, null, null, null, null, nextElement);
'
这里先生成了一个 WrappedElement 也就是一个被包装过的element。
其次:TopLevelWrapper 是一个函数,以一个函数来作为type 来 createElement。这就生成了一个 WrappedElement。
你说element就element呗,啥是被包装的element呢?我们知道React组件生成的就是一个真实的 element,而 WrappedElement 是一个本身不是React组件的html硬生生的变成element,如果是单页面应用,那就只有一个 <div id="app"></div> 需要这么搞。
简单的来说是将包裹React根组件的 容器 container,包装成了element。
'
继续往下看
instancesByReactRootID
var prevComponent = instancesByReactRootID[getReactRootID(container)];
'
根据container找到 RootID.
如果 container是一个document 就返回整个文档,而后根据整个文档,去找其上的属性 data-reactid.
如果只是普通的元素,就找到container的第一个子元素返回。而后根据这个子元素找到其上的 data-reactid属性。
一般,在初始情况下,container是不包含任何内容的。
当你更新组件的时候也就是将当前 container下的跟组件换掉的时候,这个时候 getReactRootID(container) 返回的是 上一次跟组件的 data-reactid属性值。
'
_registerComponent 方法
要想知道 instancesByReactRootID 有什么东西,就看谁给了它什么东西。
_registerComponent: function (nextComponent, container) {
var reactRootID = ReactMount.registerContainer(container);
instancesByReactRootID[reactRootID] = nextComponent;
'
从这里看到 instancesByReactRootID 里的内容是 nextComponent。而要知道 nextComponent 是什么,就得知道谁给了 _registerComponent,也就是谁调用了它。
'
return reactRootID;
},
_renderNewRootComponent 方法
_renderNewRootComponent: function (nextElement, container, shouldReuseMarkup, context) {
'
根据 nextElement 生成了 componentInstance.
nextElement是将要挂载的 element。该方法被调用是在我们的第三部分,这里先不说了。
总之你只需要知道nextElement 就是一个 element。
看一下 instantiateReactComponent方法是如何生成 componentInstance的。
'
var componentInstance = instantiateReactComponent(nextElement, null);
'
所以 instancesByReactRootID 里的内容其实就是 componentInstance.
'
var reactRootID = ReactMount._registerComponent(componentInstance, container);
}
instantiateReactComponent 模块
该模块提供了一个方法 instantiateReactComponent,该方法会将 一个 element 对象实例化为一个 ReactCompositeComponentWrapper 如下图所示:
ReactCompositeComponentWrapper 较之我们 初始提供的 element 多了很多东西。
instantiateReactComponent方法会根据 提供的element的类型不同,选择不同的处理方式。比如:
element 是 null
if (node === null || node === false) {
instance = new ReactEmptyComponent(instantiateReactComponent);
}
ReactEmptyComponent方法
'
instantiate参数还是 instantiateReactComponent 方法。
这个函数初始化了一些属性给 instance实例。
值得注意的是 _renderedComponent属性。
这里 placeholderElement 是注入进来的一个参树,值为字符串 'noscript'。
也就是说,我们再组件的render方法中返回了一个 null或者是false,就会得到一个实例。
instantiateReactComponent('noscript')
'
var ReactEmptyComponent = function (instantiate) {
this._currentElement = null;
this._rootNodeID = null;
this._renderedComponent = instantiate(placeholderElement);
};
element 是 string
else if (typeof node === 'string' || typeof node === 'number') {
instance = ReactNativeComponent.createInstanceForText(node);
}
ReactNativeComponent模块的createInstanceForText
function createInstanceForText(text) {
return new textComponentClass(text);
}
textComponentClass 方法
首先是textComponentClass是从 ReactDefaultInjection中注入的 ReactDOMTextComponent 模块
ReactDOMTextComponent模块是一个构造函数,构造函数的原型上加了很多的属性,比如一个 construct方法
construct: function (text) {
this._currentElement = text;
this._stringText = '' + text;
this._rootNodeID = null;
this._mountIndex = 0;
},:
当element 是 string的时候instantiateReactComponent方法 返回了一个 ReactDOMTextComponent的实例。
instantiateReactComponent方法会根据不同的 element特点选择不同的 构造函数来构造ReactComponent实例。
ok 就此打住,关于Element转换为实例的具体的内容请参考文章Element 实例化部分的内容
instancesByReactRootID 中的内容就是 某个组件的实例,实例中包含了一些有用的属性,比如 _currentElement 指向当前组件的 element。
总结一下:
instancesByReactRootID在初始的情况下是没有东西的。
在第三部分的时候,往 instancesByReactRootID 对象里塞入了东西。
instancesByReactRootID 存的只是根组件,其他的组件是不会往里边存的。
以上便是挂载核心方法的第一部分的内容。