上一篇大致看了一下简单组件渲染过程。走到
internalInstance.mountComponent
,没有往里细看,因为ReactCompositeComponent.mountComponent
是个比较复杂的函数,主要做了几个工作:初始化组件、渲染标签(markup)、注册监听事件,react生命周期函数也在这里执行,所以这里单独记录。本篇依然沿用之前的例子,使用简单组件,即根节点内只包含一层
class
类型的组件。class Hello extends React.Component {
render() {
return
Hello {this.props.name}
;
}
}
ReactDOM.render(
,
document.getElementById('root')
);
本篇涉及内容的基本的函数执行流程

react-mount-call-flow
可能注意到,生命周期函数
componentWillMount
和componentDidMount
并不处在同一个函数调用里,这是因为组件是递归解析的,后面会讲到。从1到2.3)基本的数据结构变动

react-mount1
1.创建一个组件,用于实例化ReactCompositeComponent
-_constructComponent(
doConstruct,
publicProps, // _currentElement.props
publicContext,
updateQueue
)
// 创建_currentElement.type实例
inst = (TopLevelWrapper){
rootID: 1,
props: {
child: {
...
props: {
"name": "World"
}
...
}
},
context: {},
refs: {},
updater: {}
}
之后在属性
ReactCompositeComponent._instance
加上该实例的引用,并在实例中用_reactInternalInstance
创建反向链接。2.执行挂载
由于

hostContainerInfo
从创建一路传递进去,基本的结构没变动,这里记录一下react-dom-container-info
基本的准备工作之后,开始在
performInitialMount
执行初始化挂载动作-this.performInitialMount(
renderedElement,
hostParent,
hostContainerInfo,
transaction,
context
)
1)执行
componentWillMount
和需要的state
更新;2)执行
inst.render
根据
inst
的类型,这里执行TopLevelWrapper
原型上的render
函数renderedElement = inst.render
=TopLevelWrapper.prototype.render {
return this.props.child;
}
将
renderedElement
添加到属性ReactCompositeComponent._renderedComponent
上3)把上一步得到的
renderedElement
‘去壳’(TopLevelWrapper
),并实例化为实际挂载的组件上一篇讲过,组件是从
ReactDOM
一层一层包装到ReactCompositeComponent
并序列化,这里做的,就是逆向操作,一步一步还原为可供实际渲染的标签。var child = _instantiateReactComponent
=instantiateReactComponent(node /** renderedElement **/, ...)
去除

TopLevelWrapper
包装
remove-top-level-wrapper
4)内一层(child)的组件挂载
步骤4)的数据结构变动

react-mount2
由于组件的根节点只有一个(记得吗,规定组件的
render
里只能存在一个根节点),所以这里会直接渲染child,而不用写循环。-ReactReconciler.mountComponent(
child,
transaction,
hostParent,
hostContainerInfo,
this._processChildContext(context),
debugID
)
-child.mountComponent //(递归调用ReactCompositeComponent.mountComponent)
inst = (ReactComponent){
...
props: {
"name": "World"
}
...
}
将步骤1中的
inst.props.child
包装成ReactComponent
实例-performInitialMount
-_renderValidatedComponentWithoutOwnerOrContext
执行实例的渲染方法
inst.render
-ReactElementValidator.createElement
=ReactElement.createElement
5)再次使用
ReactReconciler.mountComponent
-ReactReconciler.mountComponent
-ReactDOMComponent.mountComponent //(递归出口)
6)转为可用的标签(
markup
,还不是HTML
标签哦)由
document.createElement
创建标签,设置attr等属性mountChildren
=ReactChildReconciler.instantiateChildren
=traverseAllChildren // 一个字符串会生成一个ReactDOMTextComponet,由ReactReconciler.mountComponent依次处理
7)按层级执行
componentDidMount
。小结
可以看出,
ReactReconciler.mountComponent
是唯一挂载入口,所有类型(ReactCompositeComponent
、ReactDOMComponet
、ReactDOMTextComponet
)的挂载都是以这个函数为调度器。之前包装好的组件结构,在这个函数里被逐层拆解出来,并在中间加入了可控的用户方法。目前还没涉及到实际的
react
节点变为HTML
节点,即_mountImageIntoNode
方法。