When we can skillfully use React for front-end development, we will inevitably have a strong interest in the internal mechanism of React. What is the component? Is it the real DOM? What is the basis on which lifecycle functions are executed?

In this article, let’s first look at the React component implementation and mounting.

1. What are the components

First, write the simplest component:

After writing the above code, we have the component, so let’s first find out what is. Print it out with console.log:

props = props Next, let’s print

this is component A

and see what the console outputs:

We see that the props has changed, due to the nested < A / > component A div, div nested again in the text, so in the description of the < A / > object increased children attribute in the props, the value of js object describing div. In the same way, if we nested a component at multiple levels, we would add the children field and the corresponding description value in the parent object props.

The component created in ES5 using the React createClass({}) method is exactly the same as in ES6. It can also be verified by the console printout of the component results.

So how do React components that look like HTML tags but are actually objects come together?

Since our Component declarations are based on React and Component, first we open React. Js and see the following code:

When we import React from ‘React’, we are introducing the React object provided in the source code. When extends Component, you inherit from the Component class. Two caveats here:

  • Source code clearly usedmodule.exportsRather thanexport default, why can it be successfully introduced? It’s actually the Babel parser. It makes(ES6)import === (CommonJS)require. In typescript, you need to be strictexport defaultDeclaration, and therefore cannot be used in typescriptimport React from 'react'Interested readers can give it a try.
  • We could writeextends ComponentCan also writeextends React.ComponentIs there a difference between the two? The answer is no. becauseComponentisReact.ComponentThe reference. That is to say,Component === React.ComponentYou can write either in a real project.

Along the ReactComponent clues, we open the node_modules/react/lib/ReactComponent js:

The above code is a very familiar constructor, so you should be familiar with it. Also note that setState is a method defined on the prototype with two parameters, which we’ll explain in the React Update mechanism section.

This code shows that component A, which we declared at the beginning, is actually A subclass of the ReactComponent class, and its prototype has methods such as setState. So component A has A basic prototype.

summary

2. Initialize the component

After we declare A, we can customize methods inside of it, and we can also use lifecycle methods like ComponentDidMount and so on, exactly the same as when we were writing the class. The only difference is that A component class must have A render method that outputs A structure like

, which is component A

, and is mounted to the real DOM in order to trigger the lifecycle of the component and become part of the DOM tree. First, let’s look at how ES6’s “class” initializes a React component.

Put the original sample code in Babel:

The _Component is the object ReactComponent, and the _inherit method is an implementation of the extends keyword. These are all ES6 related, so we’ll leave them out for now. The key is to discover that the Render method actually calls the React. CreateElement method (which is actually the ReactElement method). Then we open ReactElement. Js:

Each component object is an object of type ReactElement created using the React. CreateElement method. In other words, ReactElment is an object that internally records component characteristics and tells React what you want to see on the screen. In ReactElement:

parameter function
? typeof Identifies a component
key DOM structure identification to improve update performance
props Substructure related information (if any, increasechildrenField/not empty) and component properties (e.gstyle)
ref A reference to the real DOM
_owner _owner= = =ReactCurrentOwner.current(reactCurrenTowner.js), which is the object that creates the current component. The default value is null.

After reading the above content, I believe you have a certain understanding of the substance of the React component. The ReactElement JS object created by executing React. CreateElement is the “React component “, which corresponds exactly to the result printed by the console. In conclusion, if we declare React components with the class keyword, they will remain JS objects of type ReactElement until they are resolved into the real DOM.

summary

To supplement the previous mind mapping:

3. Mount components

We know that we can mount custom components/native DOM/ strings in the form reactdom.render (Component,mountNode),

So how does the mounting process work?

ReactDOM. Render calls the actual internal ReactMount. Render, then execute ReactMount. _renderSubtreeIntoContainer. We can see the logic of inserting the “child DOM” into the container. Let’s look at the source code implementation:

This code is very important, all the functionality of the render function is here (click the image for a larger image).

We first to parse the incoming _renderSubtreeIntoContainer parameters:

parameter function
parentComponent The parent component of the current component, when first renderednull
nextElement The component to insert into the DOM, such ashelloWorld
container The container to be inserted, such asdocument.getElementById('root')
callback Callback function after completion

The functions of these parameters are easy to understand. Next, we carry out logical analysis line by line:

  • Line 2: Adds the current component to the previous levelpropsUnder the properties. (At the beginning of this article, the parent-child nesting relationship was explained bypropsProvide)
  • Line 4 ~ 22: CallgetTopLevelWrapperInContainerMethod to determine whether there are components in the current container, denoted asprevComponent; If there isprevComponentfortrue, to perform the update process, that is, to call_updateRootComponentMethods. If no, uninstall it. (callunmountComponentAtNodeMethods)
  • Line 24: Whether you update or uninstall, you must eventually mount to the real DOM. Look at the._renderNewRootComponentSource:

Analyze the process:

  • Line 3 appearsinstantiateReactComponentPackaging, we’ll talk about that later.
  • In line 5batchedMountComponentIntoNodeCalled as a transactionmountComponentIntoNodeThis method returns the HTML corresponding to the component, denoted as a variablemarkup. whilemountComponentIntoNodeThe final call is_mountImageIntoNode, look at the source code:

The core code is the last two lines. SetInnerHTML is a method that sets the markup to the innerHTML property of the container, thus completing DOM insertion. The precacheNode method stores the processed component objects in the cache to improve the speed of structure update.

The React component initialization and mounting process is pretty clear here. When we use the reactdom.render () method, we’ll notice that it can mount the React component, a string, or the native DOM. Now that we know that mount uses the innerHTML attribute, does React React differently for different element structures?

As we mentioned above, the component mounted the penultimate step, namely execution _renderNewRootComponent method, we see a called instantiateReactComponent method returns a processed object. We look at the source of the instantiateReactComponent:

The passed node parameter is the component parameter of the reactdom. render method. The input node and output instance can be summarized as follows:

node The actual parameter The results of
null/false empty createReactEmptyComponentcomponent
object && type === string Virtual DOM createReactDOMComponentcomponent
object && type ! == string The React components createReactCompositeComponentcomponent
string string createReactTextComponentcomponent
number digital createReactTextComponentcomponent

To sort out the process:

  • According to theReactDOM.render()With different parameters passed in, React internally creates four categories of encapsulated components, denoted ascomponentInstance.
  • Then pass it in as a parametermountComponentIntoNodeMethod to obtain the HTML corresponding to the component, denoted as a variablemarkup.
  • Will real DOM propertiesinnerHTMLSet tomarkupThat is, DOM insertion is complete.

So how do you parse the HTML in the second step? The answer is that the mountComponet method is given to the encapsulated component in the first step of encapsulating the four types of components. The execution of the method will trigger the life cycle of the component to parse out the HTML.

Of course, the most commonly used component of these four categories is the ReactCompositeComponent component, also known as the React component, which has a complete internal lifecycle and is the most critical component feature of React. The details of component types and lifecycle are covered in the next article.

4. To summarize

The React component goes from declaration to initialization to mount in one diagram:

Review: React Source Code Analysis (2): Component Types and lifecycle “React Source code Analysis (3): Detailed transaction and update queue” React source code Analysis (4): Event system contact email: [email protected]