legacyRenderSubtreeIntoContainer

Reactdom.render reactDom.render reactDom.render

In ReactDOM. Render method, logic itself is not too much, just the last return is legacyRenderSubtreeIntoContainer (null, element, container, false, callback); ; So I debug in legacyRenderSubtreeIntoContainer function;

LegacyRenderSubtreeIntoContainer receives the following parameters

  • parentComponentThe React Component passesReactDOM.renderPassed when callednullIn the compiled code to find the call uniquely passedparentComponentThe parameter isunstable_renderSubtreeIntoContainer, so skip first, later encountered in detail.

  • children: reactdom.render () the first argument, the ReactElement object in render;

Hello World!

  • container: Root node (container), as shown in the figure abovedocument.getElementById('container')Is;
  • forceHydrate: true for server rendering, false for client rendering, passReactDOM.renderThe client rendering method is false (server rendering is ignored to prevent distracting learning).
  • callback: component rendering after completion of the callback function, should not be used as I do abovechildrenThis function is added in the screenshots of “Render DOM finished” in the console after the component is rendered.
function legacyRenderSubtreeIntoContainer( parentComponent: ? React$Component<any, any>, children: ReactNodeList, container: Container, forceHydrate: true for server render, false for client render, we are looking at client render: Boolean, callback:? Function, )Copy the code

Print out the incoming calling through the render method parameters in legacyRenderSubtreeIntoContainer; Can see parentComponent, container, forceHydrate, callback is understandable, but the children of the input and the < h1 > Hello World! not quite the same, where was it handled?

Remember Babel next door? Check out Babel to experience it online

Is there something that comes back to me? If you’ve looked at the website before, Babel will translate JSX into a name called react.createElement () Function call, so the above legacyRenderSubtreeIntoContainer print in children is, in fact, by the React. The createElement method () of (the React. The createElement method not to study, don’t go to see later).

LegacyRenderSubtreeIntoContainer calls to those functions

Source code (environment specific) :

The compiled:

  • topLevelUpdateWarnings: Check whether the container is available. Error messages are serious errors

  • warnOnInvalidCallback:

Render receives two arguments, the first is the callback method, the second is the name of a flag function, render should tell us the error occurred in the render method. warnOnInvalidCallback$1(callback === undefined ? null : callback, ‘render’);

As you can see, this method is very simple, just check whether the render function callback is a function or not. If it is not a function, the console object will print an error message. The error of the two % s is behind callerName and placeholders (the console object using the callback can be found in the www.runoob.com/w3cnote/jav…

If we change the render function callback to:

ReactDOM.render( <h1>Hello World! {<Test />}</h1>, document.getElementById('container'),123 );Copy the code

Error: warnOnInvalidCallback$1 = ‘123’;

container._reactRootContainer

Next, root and fiberRoot variables are defined directly, but when the render method is called for the first time, neither of these variables has been assigned yet, and both are empty, so if(! Root){}

When to root assignment, calls the legacyCreateRootFromDOMContainer method called shouldHydrateDueToLegacyHeuristic method:

function shouldHydrateDueToLegacyHeuristic(container) { var rootElement = getReactRootElementInContainer(container); return !! (rootElement && rootElement.nodeType === ELEMENT_NODE && rootElement.hasAttribute(ROOT_ATTRIBUTE_NAME)); }Copy the code

This method is used to determine whether the server is rendering (as shown in the following figure), because the client called the render method and passed the parameter to determine whether the server is rendering is false:

After asking Baidu, I probably understand that the RENDER method can still reuse THE HTML structure of SSR in version 16, so it cannot be judged by hydrate only. Therefore shouldHydrateDueToLegacyHeuristic method made whether to have the data for the current container – reactroot judgment:

If shouldHydrate is false, it is not a server render and the following code is executed to loop to remove lastChild in the container, but there is a judgment:

if (! warned && rootSibling.nodeType === ELEMENT_NODE && rootSibling.hasAttribute(ROOT_ATTRIBUTE_NAME)) {}Copy the code

If the dom element being removed is already marked by the server rendering (with the data-reactroot attribute), the code will assume that you did something wrong and should not remove the HTML rendered by the server.

The next step is to determine whether the render method is used on the server, and give you a warning: Calling ReactDOM. Render () to Hydrate server- Rendered markup ‘+ ‘will stop working in React V18. (Rattail juice, everybody)

{ if (shouldHydrate && ! forceHydrate && ! warnedAboutHydrateAPI) { warnedAboutHydrateAPI = true; warn('render(): Calling ReactDOM.render() to hydrate server-rendered markup ' + 'will stop working in React v18. Replace the ReactDOM.render() call ' + 'with ReactDOM.hydrate() if you want React to attach to the server HTML.'); }}Copy the code

After the warning, the createLegacyRoot method is finally called, passing in the current root node container and the server render or not parameter Hydrate

return createLegacyRoot(container, shouldHydrate ? {
      hydrate: true
    } : undefined);
Copy the code

The createLegacyRoot method is re-instantiated via the ReactDOMBlockingRoot constructor:

var LegacyRoot = 0;
function createLegacyRoot(container, options) {
    return new ReactDOMBlockingRoot(container, LegacyRoot, options);
}
function ReactDOMBlockingRoot(container, tag, options) {
    this._internalRoot = createRootImpl(container, tag, options);
}
Copy the code

createRootImpl

This method finally returns root after processing is complete:

function createRootImpl(container, tag, options) { // Tag is either LegacyRoot or Concurrent Root var hydrate = options ! = null && options.hydrate === true; var hydrationCallbacks = options ! = null && options.hydrationOptions || null; var mutableSources = options ! = null && options.hydrationOptions ! = null && options.hydrationOptions.mutableSources || null; var root = createContainer(container, tag, hydrate); markContainerAsRoot(root.current, container); var rootContainerElement = container.nodeType === COMMENT_NODE ? container.parentNode : container; listenToAllSupportedEvents(rootContainerElement); if (mutableSources) { for (var i = 0; i < mutableSources.length; i++) { var mutableSource = mutableSources[i]; registerMutableSourceForHydration(root, mutableSource); } } return root; }Copy the code