内容简介:上一章jsx语法是如何解析的讲到了jsx语法是如何解析为虚拟看看下面的代码如何执行的
上一章jsx语法是如何解析的讲到了
<div>
<div>1</div>
<div>2</div>
<div>3</div>
</div>
复制代码
jsx语法是如何解析为虚拟 dom
的,接下来我将聊聊虚拟 dom
是如何挂载到真实 dom
上的。 我读的是 React^15.6.2
的源代码,因为最新的 React^16.6.3
版本,引入了 Fiber架构
,因为时间有限, Fiber
我暂时没弄的太明白,但是它主要作用是优化组件的更新,所以不影响我们理解组件的挂载.好了,下面进入正题.
看看下面的代码如何执行的
import React from "./lib/react";
import {render} from "./lib/react-dom";
const Child = () => <div>
Child
</div>
class App extends React.Component {
constructor(props){
super(props);
this.state = {
name:"leiwuyi"
}
}
render(){
return (
<div>App</div>
)
}
}
render(<div className="leiwuyi">
<div>1</div>
<div>2</div>
<div>3</div>
<App ></App>
</div>, document.getElementById("root"));
复制代码
ReactDom.render()
其实是运行了 _renderSubtreeIntoContainer
它接收了 nextElement
, container
参数. 首选将 container
这个 Element
类型的节点包装成 Component
类型,
var nextWrappedElement = React.createElement(
TopLevelWrapper,
{
child: nextElement
}
);
然后执行ReactMount._renderNewRootComponent(
nextWrappedElement,
container,
shouldReuseMarkup,
nextContext
)
复制代码
这个方法执行完毕,其实组件就已经挂载到 root
节点上去了,来看看 ReactMount._renderNewRootComponent
方法
它主要分为二个部分
// 第一部分
var componentInstance = instantiateReactCompone
nt(
nextElement,
false
);
// 第二部分
ReactUpdates.batchedUpdates(
batchedMountComponentIntoNode,
componentInstance,
container,
shouldReuseMarkup,
context
);
复制代码
第一部分 instantiateReactComponent
instantiateReactComponent
依据不同的类型产生不同的实例,每个实例都具有mountComponent方法核心方法.
| 类型 | 对应方法 |
|---|---|
null
或 undefined
|
ReactEmptyComponent
|
| 元素类型 |
ReactHostComponent.createInternalComponent( element)
|
component
的类型 |
ReactCompositeComponent
|
| 文本类型 | `ReactHostComponent.createInstanceForText(node) |
ReactHostComponent.createInternalComponent( element)
最终是运行的 ReactDOMComponent
.
第二部分 MountComponentIntoNode
就是通过事务的形式来运行 mountComponentIntoNode
方法
而 mountComponentIntoNode
方法最终是运行实例的 mountComponent
方法。
该方法会产生对应的真实 dom
节点 markup
;
产生之后然后通过 setInnerHTML(container, markup)
;插入到 container
里面.
简单的讲就是拿到真实 dom
插入到 container
里面去,这段代码执行完毕真实 dom
就挂载完成了.
具体的实现过程
在前面· nextElement
包装成 Component
类型·,所以最终产生的实例的原型对象是 ReactCompositeComponent
实例有了那么接下来就是执行 componentInstance.mountComponent方法
;
该方法执行的 ReactCompositeComponent.mountComponent
接下来看看该方法到底做了什么. 下面我就几个核心方法进行一个说明.
ReactCompositeComponent.mountComponent
第一个方法 实例化组件
this._constructComponent(
doConstruct,
publicProps,
publicContext,
updateQueue
)
产生组件的实例 如 <App > ---> new App() 就是我们常在组件中使用的this对象
第二个方法
拿到组件对应的真实dom
markup = this.performInitialMount(
renderedElement,
hostParent,
hostContainerInfo,
transaction,
context
);
复制代码
具体来看看第二个方法
this.performInitialMount
// 调用this.render或者func() 拿到虚拟dom,
if (renderedElement === undefined) {
renderedElement = this._renderValidatedComponent();
}
// 拿到一个element类型的componentInstance(上文中有的)
var child = this._instantiateReactComponent(
renderedElement,
nodeType !==
ReactNodeTypes.EMPTY /* shouldHaveDebugID */
);
this._renderedComponent = child;
// 拿到真实dom
var markup = ReactReconciler.mountComponent(
child,
transaction,
hostParent,
hostContainerInfo,
this._processChildContext(context),
debugID
);
复制代码
这里面的 ReactReconciler.mountComponent
其实是调用的 ReactDOMComponet.mountComponent
方法。
所以 this.performInitialMount
简单的讲就是 拿到组件的虚拟 dom
,然后获取它对应 的componentInstance
实例然后执行 ReactDOMComponet.mountComponent
拿到真实 dom
所以我们接下来要看看 ReactDOMComponet.mountComponent
方法的实现过程
ReactDOMComponet.mountComponent
函数前面一部分其实对 tag
的类型进行了处理 我们直接略过把 tag
当做 div
创建了一个div节点
el = ownerDocument.createElement(
this._currentElement.type
);
// 设置该节点的属性
this._updateDOMProperties(
null,
props,
transaction
);
// 构建它孩子的真实dom然后插入到该节点中去
var lazyTree = DOMLazyTree(el);
this._createInitialChildren(
transaction,
props,
context,
lazyTree
);
所以执行之后lazyTree就是一个完整的真实dom节点
复制代码
我们来看看 this._createInitialChildren
方法,
核心代码在这里
var mountImages = this.mountChildren(
childrenToUse,
transaction,
context
);
执行的是
var children = this._reconcilerInstantiateChildren(
nestedChildren,
transaction,
context
);
// 产生child对应的实例
for (var name in children) {
if (children.hasOwnProperty(name)) {
var child = children[name];
var selfDebugID = 0;
if (
"development" !== "production"
) {
selfDebugID = getDebugID(this);
}
var mountImage = ReactReconciler.mountComponent(
child,
transaction,
this,
this._hostContainerInfo,
context,
selfDebugID
);
child._mountIndex = index++;
mountImages.push(mountImage);
}
}
复制代码
看到这里,就已经很明显这是一个深度优先遍历;它的 child
又产生了一个实例然后执行 mountComponent
方法拿到真实 dom
,直到拿到最后一级孩子的真实 dom
然后不断向上递归插入父级。直到插入到最顶层这样就拿到 了Component
的真实 dom
。最后插入到 container
容器里面.
下一章将聊聊 React
的生命周期
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Python Algorithms
Magnus Lie Hetland / Apress / 2010-11-24 / USD 49.99
Python Algorithms explains the Python approach to algorithm analysis and design. Written by Magnus Lie Hetland, author of Beginning Python, this book is sharply focused on classical algorithms, but it......一起来看看 《Python Algorithms》 这本书的介绍吧!