资讯专栏INFORMATION COLUMN

React源码解析ReactDOM.render源码

joywek / 2609人阅读

摘要:的创建组件,其实根源还是调用了编译之后一般写法建议用来进行源码的跟踪链接从源码角度来看创建一个组件的过程中发生了什么。

https://github.com/jimwmg/Rea...

1 React.createClass( )


  

2 React.Component

ES6的创建组件,其实根源还是调用了createClass

编译之后

"use strict";

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn"t been initialised - super() hasn"t been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

var Welcome = function (_React$Component) {
    _inherits(Welcome, _React$Component);

    function Welcome() {
        _classCallCheck(this, Welcome);

        return _possibleConstructorReturn(this, (Welcome.__proto__ || Object.getPrototypeOf(Welcome)).apply(this, arguments));
    }

    _createClass(Welcome, [{
        key: "render",
        value: function render() {
            return React.createElement(
                "h1",
                null,
                "hello ",
                this.props.name
            );
        }
    }]);

    return Welcome;
}(React.Component);

3 function

import React from "react"
import {
  BrowserRouter as Router,
  Route,
  Link
} from "react-router-dom"
const Repo = ()=>(
this is Repo
) const Category = (props)=>{ console.log(props); return (
this is category
) } const MyTest =()=>(
  • About
  • Repo
  • Category
{console.log(props);return (
this is aabout
) }}>
{console.log(props);return (
this is a component build througth children
) }}>
) export default MyTest

ES6一般写法

const BasicExample = () => (
  
    
  • Home
  • About
  • Topics

)

tips:建议用webstorm来进行源码的跟踪链接;

4 React.js

从源码角度来看创建一个React组件的过程中发生了什么。

react.js源码github地址

var createReactClass = require("./createClass");
var React = {
  // Modern

  Children: {
    map: ReactChildren.map,
    forEach: ReactChildren.forEach,
    count: ReactChildren.count,
    toArray: ReactChildren.toArray,
    only: onlyChild
  },

  Component: ReactBaseClasses.Component,
  PureComponent: ReactBaseClasses.PureComponent,

  createElement: createElement,
  cloneElement: cloneElement,
  isValidElement: ReactElement.isValidElement,

  // Classic

  PropTypes: ReactPropTypes,
  createClass: createReactClass,
  createFactory: createFactory,
  createMixin: createMixin,

  // This looks DOM specific but these are actually isomorphic helpers
  // since they are just generating DOM strings.
  DOM: ReactDOMFactories,

  version: ReactVersion,

  // Deprecated hook for JSX spread, don"t use this for anything.
  __spread: __spread
};

看下React其实是个大的对象,对象上挂载了很多方法,当我们创建一个组件的时候,会调用createClass方法。

首先记住一点,无论是createClass还是class创建React组件,本质上都是一个函数,然后向组件(函数)prototype添加属性和方法;;

看下createClass.js源码

var _require = require("./ReactBaseClasses"),
    Component = _require.Component;

var _require2 = require("./ReactElement"),
    isValidElement = _require2.isValidElement;

var ReactNoopUpdateQueue = require("./ReactNoopUpdateQueue");
var factory = require("create-react-class/factory");

module.exports = factory(Component, isValidElement, ReactNoopUpdateQueue);

ReactBaseClasses源码地址:这里解释了组件上为何有forceUpdate,以及setState等接口;

ReactElement.js源码地址:这里解释了jsx转译之后,React到底是如何创建虚拟DOM对象的;

factory.js源码地址:这里解释了创建React组件(函数)的过程;

5 ReactDOM.js

接下来看下创建一个React组件之后,如何通过ReactDOM.render(element,container)将其加载到指定 的DOM节点的。以下只贴关键源码,其他的都附有源码地址,读者可自行查看;

ReactDOM.js源码地址

ReactDefaultInjection源码地址

源码解读

var ReactDefaultInjection = require("./ReactDefaultInjection");
ReactDefaultInjection.inject();
//上面两行是使ReactHostComponent.createInternalComponent注册方法;
var ReactDOM = {
  findDOMNode: findDOMNode,
  render: ReactMount.render,
  unmountComponentAtNode: ReactMount.unmountComponentAtNode,
  version: ReactVersion,

  /* eslint-disable camelcase */
  unstable_batchedUpdates: ReactUpdates.batchedUpdates,
  unstable_renderSubtreeIntoContainer: renderSubtreeIntoContainer
  /* eslint-enable camelcase */
};

// Inject the runtime into a devtools global hook regardless of browser.
// Allows for debugging when the hook is injected on the page.
if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== "undefined" && typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.inject === "function") {
  __REACT_DEVTOOLS_GLOBAL_HOOK__.inject({
    ComponentTree: {
      getClosestInstanceFromNode: ReactDOMComponentTree.getClosestInstanceFromNode,
      getNodeFromInstance: function (inst) {
        // inst is an internal instance (but could be a composite)
        if (inst._renderedComponent) {
          inst = getHostComponentFromComposite(inst);
        }
        if (inst) {
          return ReactDOMComponentTree.getNodeFromInstance(inst);
        } else {
          return null;
        }
      }
    },
    Mount: ReactMount,
    Reconciler: ReactReconciler
  });
}

ReactMount.js源码地址

var ReactMount = {
  //nextElement就是ReactELement,jsx语法将组件或者div,span等转化为一个ReactElement对象
  render: function (nextElement, container, callback) {
    //将ReactElement对象和container元素传递给_renderSubtreeIntoContainer函数;
    return ReactMount._renderSubtreeIntoContainer(null, nextElement, container, callback);
  },
  _renderSubtreeIntoContainer: function (parentComponent, nextElement, container, callback){
    .....//具体源码看上面源码地址
    var component = ReactMount._renderNewRootComponent(nextWrappedElement, container, shouldReuseMarkup, nextContext)  ._renderedComponent.getPublicInstance();

    return component;
  },
  //下面这个函数实现将ReactElement元素,转化为DOM元素并且插入到对应的Container元素中去;
  _renderNewRootComponent: function (nextElement, container, shouldReuseMarkup, context) {
    //Flag1 下面会有源码解释;
    //instantiateReactComponent(nextElement, false)函数返回一个组件的实例,该函数源码下面会解释;
    var componentInstance = instantiateReactComponent(nextElement, false);

    // The initial render is synchronous but any updates that happen during
    // rendering, in componentWillMount or componentDidMount, will be batched
    // according to the current batching strategy.
    //这个函数是真正的将ReactElement元素插入到DOM元素的,会进入到batchedMountComponentIntoNode函数中;
    ReactUpdates.batchedUpdates(batchedMountComponentIntoNode, componentInstance, container, shouldReuseMarkup, context);

    var wrapperID = componentInstance._instance.rootID;
    instancesByReactRootID[wrapperID] = componentInstance;

    return componentInstance;    

  }
}

//====================会进入到mountComponentIntoNode函数中
function batchedMountComponentIntoNode(componentInstance, container, shouldReuseMarkup, context) {
  var transaction = ReactUpdates.ReactReconcileTransaction.getPooled(
    /* useCreateElement */
    !shouldReuseMarkup && ReactDOMFeatureFlags.useCreateElement);
  transaction.perform(mountComponentIntoNode, null, componentInstance, container, transaction, shouldReuseMarkup, context);
  ReactUpdates.ReactReconcileTransaction.release(transaction);
}
//====================
function mountComponentIntoNode(wrapperInstance, container, transaction, shouldReuseMarkup, context) {
  var markerName;
  if (ReactFeatureFlags.logTopLevelRenders) {
    var wrappedElement = wrapperInstance._currentElement.props.child;
    var type = wrappedElement.type;
    markerName = "React mount: " + (typeof type === "string" ? type : type.displayName || type.name);
    console.time(markerName);
  }
  //Flag2 下面会有源码解释
  //markup是经过解析成功的HTML元素,该元素通过_mountImageIntoNode加载到对应的DOM元素上;
  var markup = ReactReconciler.mountComponent(wrapperInstance, transaction, null, ReactDOMContainerInfo(wrapperInstance, container), context, 0 /* parentDebugID */
                                             );

  if (markerName) {
    console.timeEnd(markerName);
  }

  wrapperInstance._renderedComponent._topLevelWrapper = wrapperInstance;
  ReactMount._mountImageIntoNode(markup, container, wrapperInstance, shouldReuseMarkup, transaction);
}
//_mountImageIntoNode
_mountImageIntoNode: function (markup, container, instance, shouldReuseMarkup, transaction) {
  !isValidContainer(container) ? process.env.NODE_ENV !== "production" ? invariant(false, "mountComponentIntoNode(...): Target container is not valid.") : _prodInvariant("41") : void 0;

  if (shouldReuseMarkup) {
    var rootElement = getReactRootElementInContainer(container);
    if (ReactMarkupChecksum.canReuseMarkup(markup, rootElement)) {
      ReactDOMComponentTree.precacheNode(instance, rootElement);
      return;
    } else {
      var checksum = rootElement.getAttribute(ReactMarkupChecksum.CHECKSUM_ATTR_NAME);
      rootElement.removeAttribute(ReactMarkupChecksum.CHECKSUM_ATTR_NAME);

      var rootMarkup = rootElement.outerHTML;
      rootElement.setAttribute(ReactMarkupChecksum.CHECKSUM_ATTR_NAME, checksum);

      var normalizedMarkup = markup;
      var diffIndex = firstDifferenceIndex(normalizedMarkup, rootMarkup);
      var difference = " (client) " + normalizedMarkup.substring(diffIndex - 20, diffIndex + 20) + "
 (server) " + rootMarkup.substring(diffIndex - 20, diffIndex + 20);

   
  if (transaction.useCreateElement) {
    while (container.lastChild) {
      container.removeChild(container.lastChild);
    }
    DOMLazyTree.insertTreeBefore(container, markup, null);
  } else {
   // 利用innerHTML将markup插入到container这个DOM元素上
      setInnerHTML(container, markup);
      // 将instance(Virtual DOM)保存到container这个DOM元素的firstChild这个原生节点上
    ReactDOMComponentTree.precacheNode(instance, container.firstChild);

  }

  if (process.env.NODE_ENV !== "production") {
    var hostNode = ReactDOMComponentTree.getInstanceFromNode(container.firstChild);
    if (hostNode._debugID !== 0) {
      ReactInstrumentation.debugTool.onHostOperation({
        instanceID: hostNode._debugID,
        type: "mount",
        payload: markup.toString()
      });
    }
  }
}

至此,从创建React组件,到组件加载到DOM 节点上的大致过程已经理顺;

接下来解释下Flag1 和Flag2标记处源码

//Flag1 下面会有源码解释;
//instantiateReactComponent(nextElement, false)函数返回一个组件的实例
var componentInstance = instantiateReactComponent(nextElement, false);

instantiateReactComponent.js源码地址

var ReactCompositeComponent = require("./ReactCompositeComponent");
var ReactEmptyComponent = require("./ReactEmptyComponent");
var ReactHostComponent = require("./ReactHostComponent");

// To avoid a cyclic dependency, we create the final class in this module
var ReactCompositeComponentWrapper = function (element) {
  this.construct(element);
};

function instantiateReactComponent(node, shouldHaveDebugID) {
  var instance;

  if (node === null || node === false) {
    //situation1:ReactEmptyComponent组件实例
    instance = ReactEmptyComponent.create(instantiateReactComponent);
  } else if (typeof node === "object") {
    var element = node;
    var type = element.type;
    if (typeof type !== "function" && typeof type !== "string") {
      var info = "";
      if (process.env.NODE_ENV !== "production") {
        if (type === undefined || typeof type === "object" && type !== null && Object.keys(type).length === 0) {
          info += " You likely forgot to export your component from the file " + "it"s defined in.";
        }
      }
      info += getDeclarationErrorAddendum(element._owner);
      !false ? process.env.NODE_ENV !== "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", type == null ? type : typeof type, info) : _prodInvariant("130", type == null ? type : typeof type, info) : void 0;
    }

    // Special case string values
    if (typeof element.type === "string") {
      //situation2:浏览器宿主实例,比如div,span等
      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.
      //situation3:
      instance = new element.type(element);

      // We renamed this. Allow the old name for compat. :(
      if (!instance.getHostNode) {
        
        instance.getHostNode = instance.getNativeNode;
      }
    } else {
      //situation4:React自定义组件,比如通过class等定义的组件;
      instance = new ReactCompositeComponentWrapper(element);
    }
  } else if (typeof node === "string" || typeof node === "number") {
   // situation5:// 元素是一个string时,对应的比如123 中的123,和situation2是一样的;
    // 本质上它不是一个ReactElement,但为了统一,也按照同样流程处理,称为ReactDOMTextComponent
    instance = ReactHostComponent.createInstanceForText(node);
  } else {
    !false ? process.env.NODE_ENV !== "production" ? invariant(false, "Encountered invalid React node of type %s", typeof node) : _prodInvariant("131", typeof node) : void 0;
  }

  if (process.env.NODE_ENV !== "production") {
    process.env.NODE_ENV !== "production" ? warning(typeof instance.mountComponent === "function" && typeof instance.receiveComponent === "function" && typeof instance.getHostNode === "function" && typeof instance.unmountComponent === "function", "Only React Components can be mounted.") : void 0;
  }

  // These two fields are used by the DOM and ART diffing algorithms
  // respectively. Instead of using expandos on components, we should be
  // storing the state needed by the diffing algorithms elsewhere.
  instance._mountIndex = 0;
  instance._mountImage = null;

  if (process.env.NODE_ENV !== "production") {
    instance._debugID = shouldHaveDebugID ? getNextDebugID() : 0;
  }

  // Internal instances should fully constructed at this point, so they should
  // not get any new fields added to them at this point.
  if (process.env.NODE_ENV !== "production") {
    if (Object.preventExtensions) {
      Object.preventExtensions(instance);
    }
  }

  return instance;
}

接下来看下这几种实例的创建源码

situation1:instance = ReactEmptyComponent.create(instantiateReactComponent);

var emptyComponentFactory;

var ReactEmptyComponentInjection = {
  injectEmptyComponentFactory: function (factory) {
    emptyComponentFactory = factory;
  }
};

var ReactEmptyComponent = {
  create: function (instantiate) {
    return emptyComponentFactory(instantiate);
  }
};

ReactEmptyComponent.injection = ReactEmptyComponentInjection;

ReactInjection.EmptyComponent.injectEmptyComponentFactory(function (instantiate) {
  // 前面比较绕,关键就是这句话,创建ReactDOMEmptyComponent对象
  return new ReactDOMEmptyComponent(instantiate);
});

// 各种null,就不分析了
var ReactDOMEmptyComponent = function (instantiate) {
  this._currentElement = null;
  this._nativeNode = null;
  this._nativeParent = null;
  this._nativeContainerInfo = null;
  this._domID = null;
};
//这里的_assign就是Object.assign函数
_assign(ReactCompositeComponentWrapper.prototype, ReactCompositeComponent, {
  _instantiateReactComponent: instantiateReactComponent
});

situation2:instance = ReactHostComponent.createInternalComponent(element);这个其实就是创建宿主元素实例

situation5:instance = ReactHostComponent.createInstanceForText(node);

在宿主元素实例上也有mountComponent方法;在生成markup的时候,对于函数,class组件实例,会递归生成新的实例,直到宿主DOM元素;

ReactDOMComponent.js源码地址

ReactDOMTextComponent.js源码地址

从源码可以看到,instance上都有mountComponent函数,和ReactCompositeComponent.js中的mountComponent函数一样,对于不同的ReactElement对象执行不同的mountComponent函数;

区别在于ReactCompositeComponent.js中的mountComponent会递归的生成instance直到ReactElement的type类型为string,然后执行ReactDOMComponent.js或者ReactDOMTextComponent.js的mountComponent函数,生成最终的DOM元素,挂载到节点上;

重点来看下

situation4:React自定义组件。

instance = new ReactCompositeComponentWrapper(element);
//组件实例上有了constructor函数执行之后的所有属性以及ReactCompositeComponent对象上的所有方法,其中包括mountComponent方法,注意上文Flag2处的
var markup = ReactReconciler.mountComponent(wrapperInstance, transaction, null, ReactDOMContainerInfo(wrapperInstance, container), context, 0 );

在instantiateReactComponent.js的源码中,如下是ReactCompositeComponentWrapper函数的定义,该函数接受ReactElement对象作为参数

var ReactCompositeComponentWrapper = function (element) {
  this.construct(element);
};

然后执行 new ReactCompositeComponentWrapper(element)的时候,会执行this.constructor(element);那么constructor是哪里来的呢?

//Object.assign
_assign(ReactCompositeComponentWrapper.prototype, ReactCompositeComponent, {
  _instantiateReactComponent: instantiateReactComponent
});
//这就使得instance = new ReactCompositeComponentWrapper(element);会执行下面的constructor方法;instance实例上有ReactCompositeComponent这个对象上的所有属性和方法,其中React组件实例上会有constructor和mountComponent函数
//注意这里并没有实例化class组件(函数),真正new class组件(函数)是在mountComponent中进行的;这里只是让instance上可以访问到ReactElement对象(type,props.....):this._currentElement = element;

ReactCompositeComponent.js源码地址

这里暂时只分析class类创建的组件渲染底层实现的代码,其余代码不贴;

var ReactCompositeComponent = {
  /**
   * Base constructor for all composite component.
   *
   * @param {ReactElement} element
   * @final
   * @internal
   */
  construct: function (element) {
    this._currentElement = element;
    this._rootNodeID = 0;
    this._compositeType = null;
    this._instance = null;
    this._hostParent = null;
    this._hostContainerInfo = null;

    // See ReactUpdateQueue
    this._updateBatchNumber = null;
    this._pendingElement = null;
    this._pendingStateQueue = null;
    this._pendingReplaceState = false;
    this._pendingForceUpdate = false;

    this._renderedNodeType = null;
    this._renderedComponent = null;
    this._context = null;
    this._mountOrder = 0;
    this._topLevelWrapper = null;

    // See ReactUpdates and ReactUpdateQueue.
    this._pendingCallbacks = null;

    // ComponentWillUnmount shall only be called once
    this._calledComponentWillUnmount = false;

    if (process.env.NODE_ENV !== "production") {
      this._warnedAboutRefsInRender = false;
    }
  },

  /**
   * Initializes the component, renders markup, and registers event listeners.
   *
   * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
   * @param {?object} hostParent
   * @param {?object} hostContainerInfo
   * @param {?object} context
   * @return {?string} Rendered markup to be inserted into the DOM.
   * @final
   * @internal
   */
  mountComponent: function (transaction, hostParent, hostContainerInfo, context) {
    var _this = this;

    this._context = context;
    this._mountOrder = nextMountID++;
    this._hostParent = hostParent;
    this._hostContainerInfo = hostContainerInfo;
//ReactElement对象中的props,context,type等的声明;
    var publicProps = this._currentElement.props;
    var publicContext = this._processContext(context);

    var Component = this._currentElement.type;//class声明的React组件(函数)_constructComponentWithoutOwner函数中初始化为实例对象;

    var updateQueue = transaction.getUpdateQueue();

    // Initialize the public class
    var doConstruct = shouldConstruct(Component);
    //这里的inst就是new class组件生成的实力对象;_constructComponent下面有贴上源码;
    var inst = this._constructComponent(doConstruct, publicProps, publicContext, updateQueue);
    var renderedElement;
    // These should be set up in the constructor, but as a convenience for
    // simpler class abstractions, we set them up after the fact.
    //将ReactElement对象上的props,context,refs给到React组件的实例对象;
    //这就是为什么在组件中通过this.props可以访问到对应的属性值的原因;
    /**
    class Welcome extends React.Component {
         render(){
             return 

hello {this.props.name}

} } const element = 通过JSX生成ReactElement对象,生成这个对象,会成为instance = new ReactCompositeComponentWrapper(element);对象的一个属性,_currentElement;同时instance上有mountComponent方法;当Flag2处生成markup的时候,会调用这个方法,在这个方法中会new class组件,生成实例对象; */ inst.props = publicProps; inst.context = publicContext; inst.refs = emptyObject; inst.updater = updateQueue; this._instance = inst; // Store a reference from the instance back to the internal representation ReactInstanceMap.set(inst, this); var initialState = inst.state; if (initialState === undefined) { inst.state = initialState = null; } !(typeof initialState === "object" && !Array.isArray(initialState)) ? process.env.NODE_ENV !== "production" ? invariant(false, "%s.state: must be set to an object or null", this.getName() || "ReactCompositeComponent") : _prodInvariant("106", this.getName() || "ReactCompositeComponent") : void 0; this._pendingStateQueue = null; this._pendingReplaceState = false; this._pendingForceUpdate = false; var markup; //对于class创建的React组件来说,renderedElement = inst.render();下面的函数内部会调用组件实例的render方法;这里不在深入研究; if (inst.unstable_handleError) { markup = this.performInitialMountWithErrorHandling(renderedElement, hostParent, hostContainerInfo, transaction, context); } else { //这里进行递归的生成组件实例,直到renderElement是宿主DOM元素的时候;下面有源码; markup = this.performInitialMount(renderedElement, hostParent, hostContainerInfo, transaction, context); } if (inst.componentDidMount) { if (process.env.NODE_ENV !== "production") { transaction.getReactMountReady().enqueue(function () { measureLifeCyclePerf(function () { return inst.componentDidMount(); }, _this._debugID, "componentDidMount"); }); } else { transaction.getReactMountReady().enqueue(inst.componentDidMount, inst); } } return markup; }, performInitialMount: function (renderedElement, hostParent, hostContainerInfo, transaction, context) { var inst = this._instance; var debugID = 0; if (process.env.NODE_ENV !== "production") { debugID = this._debugID; } if (inst.componentWillMount) { if (process.env.NODE_ENV !== "production") { measureLifeCyclePerf(function () { return inst.componentWillMount(); }, debugID, "componentWillMount"); } else { inst.componentWillMount(); } // When mounting, calls to `setState` by `componentWillMount` will set // `this._pendingStateQueue` without triggering a re-render. if (this._pendingStateQueue) { inst.state = this._processPendingState(inst.props, inst.context); } } // If not a stateless component, we now render if (renderedElement === undefined) { renderedElement = this._renderValidatedComponent(); } var nodeType = ReactNodeTypes.getType(renderedElement); this._renderedNodeType = nodeType; //如果是child是class生成的ReactElement对象,即type类型为函数,此时child上的mountComponent引用的是而ReactCompositeComponent.js中的mountComponent,则继续递归生成markup,直到child是宿主ReactElement对象,即type类型为字符串,此时child上mountComponent引用的是,ReactDOMComponent.js中的mountComponent,则最终生成DOM元素,插入到节点中; var child = this._instantiateReactComponent(renderedElement, nodeType !== ReactNodeTypes.EMPTY /* shouldHaveDebugID */ ); this._renderedComponent = child; //ReactReconciler.mountComponent会调用组件实例的mountComponent函数,这里对于函数组件;会调用ReactCompositeComponent.js中的mountComponent //这里进行递归调用ReactCompositeComponent.js中的mountComponent函数,而ReactCompositeComponent.js中的mountComponent中又调用performInitialMount形成递归; //直到组件是宿主DOM对象的时候,生成markup的时候,会调用 var markup = ReactReconciler.mountComponent(child, transaction, hostParent, hostContainerInfo, this._processChildContext(context), debugID); if (process.env.NODE_ENV !== "production") { if (debugID !== 0) { var childDebugIDs = child._debugID !== 0 ? [child._debugID] : []; ReactInstrumentation.debugTool.onSetChildren(debugID, childDebugIDs); } } return markup; }, _constructComponent: function (doConstruct, publicProps, publicContext, updateQueue) { if (process.env.NODE_ENV !== "production" && !doConstruct) { ReactCurrentOwner.current = this; try { return this._constructComponentWithoutOwner(doConstruct, publicProps, publicContext, updateQueue); } finally { ReactCurrentOwner.current = null; } } else { return this._constructComponentWithoutOwner(doConstruct, publicProps, publicContext, updateQueue); } }, _constructComponentWithoutOwner: function (doConstruct, publicProps, publicContext, updateQueue) { var Component = this._currentElement.type; if (doConstruct) { if (process.env.NODE_ENV !== "production") { return measureLifeCyclePerf(function () { //这里的Component就是ReactElement中的type,new该type的时候,如果是class声明的,会直接执行class类中的constructor函数;返回一个组件实例对象; return new Component(publicProps, publicContext, updateQueue); }, this._debugID, "ctor"); } else { return new Component(publicProps, publicContext, updateQueue); } } // This can still be an instance in case of factory components // but we"ll count this as time spent rendering as the more common case. if (process.env.NODE_ENV !== "production") { return measureLifeCyclePerf(function () { return Component(publicProps, publicContext, updateQueue); }, this._debugID, "render"); } else { return Component(publicProps, publicContext, updateQueue); } }, }

接下来看下Flag2的解释

var markup = ReactReconciler.mountComponent(wrapperInstance, transaction, null, ReactDOMContainerInfo(wrapperInstance, container), context, 0 )

ReactReconciler.js源码地址

var ReactReconciler = {
  /**
   * Initializes the component, renders markup, and registers event listeners.
   *
   * @param {ReactComponent} internalInstance
   * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
   * @param {?object} the containing host component instance
   * @param {?object} info about the host container
   * @return {?string} Rendered markup to be inserted into the DOM.
   * @final
   * @internal
   */
  mountComponent: function (internalInstance, transaction, hostParent, hostContainerInfo, context, parentDebugID) // 0 in production and for roots
  {
    if (process.env.NODE_ENV !== "production") {
      if (internalInstance._debugID !== 0) {
        ReactInstrumentation.debugTool.onBeforeMountComponent(internalInstance._debugID, internalInstance._currentElement, parentDebugID);
      }
    }
    //注意这里internalInstance.mountComponent其实就是ReactCompositeComponent.js中的mountComponent方法;
    var markup = internalInstance.mountComponent(transaction, hostParent, hostContainerInfo, context, parentDebugID);
    if (internalInstance._currentElement && internalInstance._currentElement.ref != null) {
      transaction.getReactMountReady().enqueue(attachRefs, internalInstance);
    }
    if (process.env.NODE_ENV !== "production") {
      if (internalInstance._debugID !== 0) {
        ReactInstrumentation.debugTool.onMountComponent(internalInstance._debugID);
      }
    }
    return markup;
  },
  ........
  //其他方法.......
}

6 总结

React.js负责创建一个虚拟DOM对象,这个对象以一个大的ReactElement对象的形式存在;

ReactDOM.js负责将虚拟DOM对象挂在到真正的DOM 根节点上,

对于class组件,会调用其render函数的返回值作为renderedElement的值,进行递归挂载

对于宿主DOM对象,则直接将其挂载

react如何将ReactElement加载到DOM

ReactCreateClass源码解析

ReactDOM.render源码解析

ReactCompositeComponent的源码实现

babel转译网站

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/89089.html

相关文章

  • react解析: render的FiberRoot(三)

    摘要:查看创建核心函数源码行调用函数创建是相关,不用管源码行这个指的是调用创建,下面我们将会说到对象源码行源码行函数中,首先创建了一个,然后又创建了一个,它们两者还是相互引用。 感谢 yck: 剖析 React 源码解析,本篇文章是在读完他的文章的基础上,将他的文章进行拆解和加工,加入我自己的一下理解和例子,便于大家理解。觉得yck写的真的很棒 。React 版本为 16.8.6,关于源码的...

    muddyway 评论0 收藏0
  • ReactDOM.render源码解析-1

    摘要:本文将对源码做一个初步解析。首先在方法中校验参数是否合法,然后调用在中,调用拿到了的一个实例,调用拿到了,用于注入到,和作为返回值,调用开始调度过程在中,首先清理了中的所有子节点,然后了一个并返回是如何调度的是一个什么样的类的操作是在哪里 初步看了react-dom这个包的一些源码,发现其比react包要复杂得多,react包中基本不存在跨包调用的情况,他所做的也仅仅是定义了React...

    _Zhao 评论0 收藏0
  • React源码解析ReactDOM.render()

    摘要:一更新的方式有三种渲染接下来,我们就来看下源码二作用在提供的里渲染一个元素,并返回对该组件的引用常见的用法是这个官网网址源码服务端使用方法渲染节点是让服务端尽可能复用节点,提高性能元素容器应用渲染结束后,调用的函数错误抓取方法本质是返回 showImg(https://segmentfault.com/img/remote/1460000020064414?w=1240&h=641);...

    iKcamp 评论0 收藏0
  • 剖析 React 源码render 流程(二)

    摘要:就是,如果你不了解这个的话可以阅读下相关文档,是应用初始化时就会生成的一个变量,值也是,并且这个值不会在后期再被改变。这是我的剖析 React 源码的第三篇文章,如果你没有阅读过之前的文章,请务必先阅读一下 第一篇文章 中提到的一些注意事项,能帮助你更好地阅读源码。 文章相关资料 React 16.8.6 源码中文注释,这个链接是文章的核心,文中的具体代码及代码行数都是依托于这个仓库 热身...

    My_Oh_My 评论0 收藏0
  • React 源码深度解读(一):首次DOM元素渲染 - Part 1

    摘要:调用栈是这样的这里生成的我们将其命名为,它将作为参数传入到。整个的调用栈是这样的组件间的层级结构是这样的到此为止,顶层对象已经构造完毕,下一步就是调用来自的方法,进行页面的渲染了。通过表达的结构最终会转化为一个纯对象,用于下一步的渲染。 欢迎关注我的公众号睿Talk,获取我最新的文章:showImg(https://segmentfault.com/img/bVbmYjo); 一、前言...

    daydream 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<