函数组件经过babel转译之后的结果:
<FunctionComponent />
React.createElement(FunctionComponent, null);
FunctionComponent是一个函数,所以我们需要在mount中增加对函数的判断:
function createDOM(vdom) {
if (!vdom) return null;
let { type, props } = vdom;
let dom;//真实DOM
if (type === REACT_TEXT) {//如果这个元素是一个文本的话
dom = document.createTextNode(props.content);
} else if (typeof type === 'function') {
return mountFunctionComponent(vdom);
}
function mountFunctionComponent(vdom) {
let { type, props } = vdom;
//此处的type就是上面的FunctionComponent
let renderVdom = type(props);
//这个代码我们现在还没有用,后面进行组件更新使用的
vdom.oldRenderVdom = renderVdom;
return createDOM(renderVdom);
}
对于类组件,babel编译之后依然是一个函数
react中增加了Component类:
class Component {
static isReactComponent = true //当子类继承父类的时候 ,父类的静态属性也是可以继承的
constructor(props) {
this.props = props;
}
}
react-dom中增加了type.isReactComponent的分支,调用mountClassComponent:
function createDOM(vdom) {
if (!vdom) return null;
let { type, props } = vdom;
let dom;//真实DOM
if (type === REACT_TEXT) {//如果这个元素是一个文本的话
dom = document.createTextNode(props.content);
} else if (typeof type === 'function') {//如果类型是一个函数的话
if (type.isReactComponent) {//说明它是一个类组件
return mountClassComponent(vdom);
} else {
return mountFunctionComponent(vdom);
}
mountClassComponent的实现:
function mountClassComponent(vdom) {
let { type: ClassComponent, props } = vdom;
let classInstance = new ClassComponent(props);
let renderVdom = classInstance.render();
classInstance.oldRenderVdom = vdom.oldRenderVdom = renderVdom;
return createDOM(renderVdom);
}
createDOM 里面处理逻辑可分为两类:
1、将vdom参数本身对应的虚拟DOM转换为真实DOM
2、处理子节点
但对于类组件和函数组件来说,通常情况只有以上第1步,它们的调用路径,比较多的一种情况是其他节点在遍历子节点时遇到类组件和函数组件,然后进入到createDOM方法中执行