In the previous article, we introduced how the top-level object ReactComposite Component [T] was constructed. Next, let's look at what batched Mount Component IntoNode did.
The call stack described in this article looks like the following:
|=ReactMount.render(nextElement, container, callback) ___ |=ReactMount._renderSubtreeIntoContainer() | |-ReactMount._renderNewRootComponent() | |-instantiateReactComponent() | |~batchedMountComponentIntoNode() upper half |~mountComponentIntoNode() (Platform independent) |-ReactReconciler.mountComponent() | |-ReactCompositeComponent.mountComponent() | |-ReactCompositeComponent.performInitialMount() | |-instantiateReactComponent() _|_ |-ReactDOMComponent.mountComponent() lower half |-_mountImageIntoNode() (HTML DOM Relevant) _|_
If we look at the source code, we will notice a lot of transaction-related code, which we will ignore for the time being, and will be explained in subsequent articles. For the time being, it can be understood that when transaction. performance is called, it is actually a function call to the first parameter. After skipping some template code, it's actually mountComponentIntoNode that does everything.
// File location: src/renderers/dom/client/ReactMount.js function mountComponentIntoNode( wrapperInstance, // ReactCompositeComponent[T] container, // document.getElementById("root") transaction, shouldReuseMarkup, context ) { ... var markup = ReactReconciler.mountComponent( wrapperInstance, transaction, null, ReactDOMContainerInfo(wrapperInstance, container), context, 0 /* parentDebugID */ ); ... ReactMount._mountImageIntoNode( markup, container, wrapperInstance, shouldReuseMarkup, transaction ); }
ReactReconciler.mountComponent is used to create DOM elements, while ReactMount._mountImageIntoNode is used to mount the newly created DOM elements onto the page. ReactReconciler.mountComponent calls the mountComponent method of ReactCompositeComponent[T]. Before looking at the mountComponent method, you also need to prepare hostContainerInfo, which is generated by ReactDOMContainerInfo:
// File location: src/renderers/shared/stack/reconciler/ReactContainerInfo.js function ReactDOMContainerInfo( topLevelWrapper, // ReactCompositeComponent[T] node // document.getElementById("root") ) { var info = { _topLevelWrapper: topLevelWrapper, _idCounter: 1, _ownerDocument: node ? node.nodeType === DOC_NODE_TYPE ? node : node.ownerDocument : null, _node: node, _tag: node ? node.nodeName.toLowerCase() : null, _namespaceURI: node ? node.namespaceURI : null, }; ... return info; }
Now the relationship between the instances is as follows:
Further look at mountComponent method:
// File location: src/renderers/shared/stack/reconciler/ReactComposite Component.js mountComponent: function ( transaction, hostParent, hostContainerInfo, context ) { ... // This. _current Element is ReactElement [2] (TopLevel Wrapper) var publicProps = this._currentElement.props; var publicContext = this._processContext(context); // TopLevelWrapper var Component = this._currentElement.type; ... // Initialize the public class var doConstruct = shouldConstruct(Component); // Generate TopLevel Wrapper instance var inst = this._constructComponent( doConstruct, publicProps, publicContext, updateQueue ); ... var markup; ... markup = this.performInitialMount(renderedElement, hostParent, hostContainerInfo, transaction, context ... return markup; }, performInitialMount: function (renderedElement, hostParent, hostContainerInfo, transaction, context) { // TopLevel Wrapper instance var inst = this._instance; ... // If not a stateless component, we now render if (renderedElement === undefined) { // The return value is ReactElement[1] renderedElement = this._renderValidatedComponent(); } // Return ReactNodeTypes.HOST var nodeType = ReactNodeTypes.getType(renderedElement); this._renderedNodeType = nodeType; // instantiateReactComponent.js var child = this._instantiateReactComponent( renderedElement, nodeType !== ReactNodeTypes.EMPTY /* shouldHaveDebugID */ ); this._renderedComponent = child; var markup = ReactReconciler.mountComponent( child, transaction, hostParent, hostContainerInfo, this._processChildContext(context), debugID ); ... return markup; },
When running to var child = this._instantiateReactComponent, the instantiateReactComponent file mentioned in the previous article is called:
// File location: src/renderers/shared/stack/reconciler/instantiateReactComponent.js function instantiateReactComponent(node, shouldHaveDebugID) { var instance; ... } else if (typeof node === 'object') { ... // element.type is `h1' if (typeof element.type === 'string') { instance = ReactHostComponent.createInternalComponent(element); } return instance; }
ReactDom will execute ReactDefaultInjection.inject() to inject ReactDOMComponent into ReactHost Component when it is executed. ReactHostComponent.createInternalComponent will eventually call ReactDOMComponent:
// File location: src/renderers/dom/shared/ReactDomComponent.js function ReactDOMComponent(element) { // h1 var tag = element.type; validateDangerousTag(tag); // ReactElement[1] this._currentElement = element; this._tag = tag.toLowerCase(); this._namespaceURI = null; this._renderedChildren = null; this._previousStyle = null; this._previousStyleCopy = null; this._hostNode = null; this._hostParent = null; this._rootNodeID = 0; this._domID = 0; this._hostContainerInfo = null; this._wrapperState = null; this._topLevelWrapper = null; this._flags = 0; }
We named the returned instance ReactDOMComponent[ins].
ReactReconciler.mountComponent calls the mountComponent method of ReactDomComponent, which involves HTML DOM-related content, which we will explain in the next article.
Now let's look at the relationship between the examples:
The call stack so far:
|=ReactMount.render(nextElement, container, callback) ___ |=ReactMount._renderSubtreeIntoContainer() | |-ReactMount._renderNewRootComponent() | |-instantiateReactComponent() | |~batchedMountComponentIntoNode() upper half |~mountComponentIntoNode() (Platform independent) |-ReactReconciler.mountComponent() | |-ReactCompositeComponent.mountComponent() | |-ReactCompositeComponent.performInitialMount() | |-instantiateReactComponent() _|_ |-ReactDOMComponent.mountComponent() lower half |-_mountImageIntoNode() (HTML DOM Relevant next commentary) _|_