1、VirtualDOM的渲染流程
一般情况下,React内我们用这两种方法写一个组件:
function App() {
return (
<div>Hello React</div>
);
}
或者
const App = React.createElement('div', null, 'Hello React');
这两种方法的本质都是调用React.createElement(),该方法返回一个JavaScript对象。这个对象如下所示: 注意 ReactElement是一个函数,React.createElement()的最后一行代码就是调用该函数并返回其结果
var ReactElement = function (type, key, ref, self, source, owner, props) {
var element = {
// react中防止XSS注入的变量,也是标志这个是react元素的变量,稍后会讲
$$typeof: REACT_ELEMENT_TYPE,
// 构建属于这个元素的属性值
type: type,
key: key,
ref: ref,
props: props,
// 记录一下创建这个元素的组件
_owner: owner,
};
return element;
};
经过以上步骤,我们得到的结果是一个Javascript对象,该Javascript对象就是虚拟DOM。接下来,虚拟Dom是怎么变成真实Dom的?通过以下函数:ReactDOM.render(element,container)。
那么render函数是如何把虚拟Dom渲染成真实Dom的?
1、假设现在有一个test文本:“Hello,World!”,我们首先实例化一个ReactDOMTextComponent对象(它叫做渲染器),该对象(渲染器)有一个方法mountComponent。如下所示:
用文字描述mountComponent做了什么事。第一步:调用DOMLazyTree生成lazyTree对象。lazyTree是一个Javascript对象,其node属性就是该对象对应的真实DOM。然后调用queueChild把Text文本插入其所对应的真实DOM。queueChild如下所示:
function queueChild(parentTree, childTree) {
if (enableLazy) {
parentTree.children.push(childTree);
} else {
parentTree.node.appendChild(childTree.node);
}
}
2、假设现有一个原子组件(例如div,span,img),我们首先实例化一个ReactDOMComponent对象。
不能完全看懂,挑会的讲。第一步,createElement根据虚拟dom的type,创建相应的元素。第二步,_updateDOMProperties更新该元素的属性(例如class,style等等属性)。第三步_createInitialChildren创建该元素的子元素。具体看_createInitialChildren内部,一般直接进入else逻辑:第一种情况是child就是一个text文本,于是调用DOMLazyTree生成一个对象,然后用queueChild把对象加入parentTree的children中。第二种情况child是component,于是调用mountChildren()。不知道mountChildren内部是啥,根据名字猜测和moutComponent功能一样,只不过返回的是数组而已。
3、假设现有一个组合组件。
看右图_renderValidateComponent会调用构造器的render()方法。renderedElement就是一个虚拟DOM。getType()获取该虚拟DOM的type。根据该type初始化一个渲染器。重复1或者2