美文网首页程序员
react源码解析(组件的挂载)

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

作者: 悠哈121 | 来源:发表于2018-07-15 12:52 被阅读0次
    //接上一篇,我们这里主要讲的是这一句代码做了什么,同上一篇文章,我们也是依次去找函数实现
      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

    相关文章

      网友评论

        本文标题:react源码解析(组件的挂载)

        本文链接:https://www.haomeiwen.com/subject/vyqppftx.html