程序员

react源码解析(组件的挂载)

2018-07-15  本文已影响0人  悠哈121
//接上一篇,我们这里主要讲的是这一句代码做了什么,同上一篇文章,我们也是依次去找函数实现
  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

上一篇 下一篇

猜你喜欢

热点阅读