//接上一篇,我们这里主要讲的是这一句代码做了什么,同上一篇文章,我们也是依次去找函数实现
ReactDOM.render(<Hello/>,document.getElementById('container'));
image.png
image.png
_renderSubtreeIntoContainer: function (parentComponent, nextElement, container, callback) {
//...我们来解释一下参数parentComponent:当前组件的父组件,第一次渲染时为null,nextElement:要插入DOM中的组件,如Hello,container:要插入的容器,如document.getElementById('container')
/*这句代码是把当前的组件添加到上一级的props属性下,前一篇https://www.jianshu.com/p/9bd7ed52764e已经介绍过reactElement的作用,这里不再赘述l*/
var nextWrappedElement = ReactElement(TopLevelWrapper, null, null, null, null, null, nextElement);
//判断当前容器下是否存在组件,如果存在,执行更新,不存在则卸载
var prevComponent = getTopLevelWrapperInContainer(container);
if (prevComponent) {
var prevWrappedElement = prevComponent._currentElement;
var prevElement = prevWrappedElement.props;
if (shouldUpdateReactComponent(prevElement, nextElement)) {
var publicInst = prevComponent._renderedComponent.getPublicInstance();
var updatedCallback = callback && function () {
callback.call(publicInst);
};
ReactMount._updateRootComponent(prevComponent, nextWrappedElement, nextContext, container, updatedCallback);
return publicInst;
} else {
ReactMount.unmountComponentAtNode(container);
}
}
//最终的组件都是要挂在dom上的
var component = ReactMount._renderNewRootComponent(nextWrappedElement, container, shouldReuseMarkup, nextContext)._renderedComponent.getPublicInstance();
if (callback) {
callback.call(component);
}
return component;
}
//接下来看._renderNewRootComponent的源码
image.png
先找第一个红框出现的函数
function instantiateReactComponent(node, shouldHaveDebugID) {
var instance;
if (node === null || node === false) {
instance = ReactEmptyComponent.create(instantiateReactComponent);
} else if (typeof node === 'object') {
var element = node;
!(element && (typeof element.type === 'function' || typeof element.type === 'string')) ? "development" !== 'production' ? invariant(false, 'Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: %s.%s', element.type == null ? element.type : typeof element.type, getDeclarationErrorAddendum(element._owner)) : _prodInvariant('130', element.type == null ? element.type : typeof element.type, getDeclarationErrorAddendum(element._owner)) : void 0;
// Special case string values
if (typeof element.type === 'string') {
instance = ReactHostComponent.createInternalComponent(element);
} else if (isInternalComponentType(element.type)) {
// This is temporarily available for custom components that are not string
// representations. I.e. ART. Once those are updated to use the string
// representation, we can drop this code path.
instance = new element.type(element);
// We renamed this. Allow the old name for compat. :(
if (!instance.getHostNode) {
instance.getHostNode = instance.getNativeNode;
}
} else {
instance = new ReactCompositeComponentWrapper(element);
}
} else(typeof node === 'string' || typeof node === 'number') {
instance = ReactHostComponent.createInstanceForText(node);
}
return instance;
}
//这里的代码太杂乱了,我们简化一下(其实就是根据我们传入的node的类型, instantiateReactComponent会相应的将我们传入的node创建相应的四大类封装组件)
function instantiateReactComponent(node){
//ReactDOM.render(node,container) node为空
if (node === null || node === false) {
return ReactEmptyComponent.create(instantiateReactComponent);
}
//文本节点的情况
if(typeof node === 'string' || typeof node === 'number'){
return new ReactDOMTextComponent(node);
}
//浏览器默认节点的情况
if(typeof node === 'object' && typeof node.type === 'string'){
//注意这里,使用了一种新的component
return new ReactDOMComponent(node);
}
//自定义的元素节点
if(typeof node === 'object' && typeof node.type === 'function'){
//注意这里,使用新的component,专门针对自定义元素
return new ReactCompositeComponent(node);
}
}
/*接下来我们看第二个红框batchedMountComponentIntoNode以事务的形式调用mountComponentIntoNode,
该方法会调用mountComponent的方法,mountComponent方法会将节点内容拼接返回一个html记为markup。
而mountComponentIntoNode最终调用的是_mountImageIntoNode,_mountImageIntoNode中的方法setInnerHTML(container, markup)
将组装好的html拼接的组件字符串插入到html页面的id= container中*/
1.上一篇:react源码解析(组件声明与初始化)https://www.jianshu.com/p/9bd7ed52764e
网友评论