[Module 1] Systematic and in-depth study of basic knowledge

How does JSX code “turn” into DOM?

Although there are more and more frameworks for JSX syntax, React is still the most relevant one. React and JSX were controversial when they first appeared in 2013, but now more and more people are saying “Wow!” So how does JSX code ‘suddenly’ become DOM? The answer may be found in this chapter.

1. Three “big questions” about JSX

In our daily React development work, we are used to using JSX to describe the React component content. The JSX syntax itself is familiar to every React developer. Let’s use a simple React component to quickly wake up jSX-related memories. The value returned by the Render method in the following component is populated with JSX code:

import React from "react";
import ReactDOM from "react-dom";
class App extends React.Component {
  render() {
    return (
      <div className="App">
        <h1 className="title">I am the title</h1>
        <p className="content">I am the content</p>
      </div>
    );
  }
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Copy the code

To find out the story behind JSX. For this “back story”, we will first discuss the three most representative and distinctive questions:

1) What is the nature of JSX and what is the relationship between JSX and JS?

2) Why use JSX? What are the consequences of not using it?

3) What is the functional module behind JSX and what does this functional module do?

If we can’t come up with a clear and systematic way of thinking about these three issues, it’s likely that we’ve oversimplified JSX. Most people simply understand it as a template syntax, but in fact, JSX is a feature of the React framework, and it has a lot to do with how React itself works. The answers to the above three questions are precisely hidden in this layer of “connection”. In many interview scenarios, candidates have no idea about this layer of “connection”, which is an important basis to evaluate whether they are “senior” in React.

2. Solutions to three major questions

1) The essence of JSX: JavaScript syntactic extensions

JSX is a syntactic extension to JavaScript. It’s close to the template language, but it has all the capabilities of JavaScript. The “syntactic extension” part of the definition above is hardly ambiguous, but “it has full JavaScript capabilities” is always confusing. JSX and JS are not in the same league. This leads to the question of how JSX syntax works in JavaScript.

(1) To answer the question of how JSX syntax works in JavaScript, let’s start with Babel.

Facebook describes JSX as an “extension” of JavaScript, not a “version” of JavaScript, which directly determines that browsers don’t support JSX the way JavaScript does naturally. So how does JSX syntax work in JavaScript? JSX will compile to react.createElement (), which will return a JS object called “React Element”.

When JSX is compiled, it becomes a call to react. createElement, so don’t worry about what the React.createElement API actually does (I’ll cover that separately below). Let’s start with how this “compile” works: The “compile” action is done by Babel.

(2) So what is Babel?

Babel is a toolchain for converting ECMAScript 2015+ version code into backwardly compatible JavaScript syntax so it can run in current and older versions of browsers or other environments. – the Babel’s official website

For example, the ES2015+ release introduced a new syntax called “template strings,” which is not compatible with some older browsers. Here is an example of template string code:

var name = "Guy Fieri"; var place = "Flavortown"; `Hello ${name}, ready for ${place}? `;Copy the code

Babel can then convert this code into ES5 code that most older browsers will recognize, as shown below:

var name = "Guy Fieri"; var place = "Flavortown"; "Hello ".concat(name, ", ready for ").concat(place, "?" );Copy the code

Similarly, Babel has the ability to translate JSX syntax into JavaScript code.

(3) What exactly will Babel do with JSX?

Take a look at Babel’s playground. Here again type the JSX part of the sample code at the beginning of this article:

As you can see, all JSX tags are converted to the React. CreateElement call, which means that JSX is actually written to React. CreateElement, which looks a bit like HTML, but only “looks like”. The essence of JSX is the react. createElement syntax for JavaScript calls, which perfectly echoes the React official statement that JSX has JavaScript capabilities.

2) React uses JSX syntax motivation

To put it another way, JSX is equivalent to a call to React. CreateElement. Why not create elements with React.

The reason is simple enough. Let’s look at the JSX code for a relatively complex component compared to the react.createElement call. Their respective shapes are shown below, with the JSX code on the left and the react.createElement call on the right:

You will find that JSX code is hierarchical and nested in a way that is consistent with actual functionality. The React.createElement code, on the other hand, is a very confusing mix that is not only unfriendly to read but also hard to write.

JSX syntactic sugar allows front-end developers to create virtual DOM using htML-like tag syntax that we are most familiar with, reducing learning costs while improving r&d efficiency and experience.

At this point, we can also fully understand that “JSX is a syntactic extension of JavaScript, which is close to the template language, but has full JavaScript capabilities.” The meaning behind this definition. What about react. createElement? Here is an in-depth look at the relevant source code.

3) Functional modules behind JSX

(1) How to map JSX to DOM: createElement source code

Before the analysis begins, try to read the line-by-line parsing of the appended source code to get a general idea of what each line of createElement does:
/ / export function createElement(type, config, Children) {// propName is used to store element attributes that need to be used later. // Props = {}; // props = {}; // let key = null; // Let key = null; let ref = null; let self = null; let source = null; // the config object stores the element attribute if (config! If (hasValidRef(config)) {ref = config.ref; If (hasValidKey(config)) {key = "+ config.key; } self = config.__self === undefined ? null : config.__self; source = config.__source === undefined ? null : config.__source; For (propName in config) {if (// Filter out any properties that can be pushed into the props object hasOwnProperty.call(config, propName) && / ! RESERVED_PROPS.hasOwnProperty(propName) ) { props[propName] = config[propName]; Const childrenLength = arguments.length - 2; const childrenLength = arguments.length - 2; // If type and config are removed, there is only one argument left, If (childrenLength === 1) {// Assign this parameter to props. Children = children; } else if (childrenLength > 1) {const childArray = Array(childrenLength); For (let I = 0; i < childrenLength; i++) { childArray[i] = arguments[i + 2]; } // Finally, assign this array to props. Children props. Children = childArray; } // defaultProps if (type && type.defaultprops) {const defaultProps = type.defaultprops; for (propName in defaultProps) { if (props[propName] === undefined) { props[propName] = defaultProps[propName]; }}} // Finally returns a call to ReactElement execution method, And incoming just treated parameters return ReactElement (type, key, ref, the self, the source, ReactCurrentOwner. Current, props,); }Copy the code

Through the preliminary display of the source details, the next step to extract the key knowledge points and core ideas in the source code.

(2) Input interpretation: What information is needed to create an element

Let’s take a look at the method input:

export function createElement(type, config, children)
Copy the code

As you can see, createElement has three inputs that contain all the information React needs to know to create an element. Type: indicates the type of a node. It can be a standard HTML tag string like “H1” or “div”, or it can be a React component type or React Fragment type. Config: Passed in as an object, all properties of the component are stored as key-value pairs in the Config object. Children: is passed in as an object that records nested content between component tags, known as “child nodes” or “child elements.”

If the text description seems abstract to you, the following call example can help you improve your understanding of the concept:

React.createElement("ul", {// Pass the attribute key value pair className: CreateElement ("li", {key: "1"}, "1"), react. createElement("li", {key: "1"}); "2"}, "2"));Copy the code

The DOM structure for this call is as follows:

<ul className="list">
  <li key="1">1</li>
  <li key="2">2</li>
</ul>
Copy the code

With a general understanding of the form and content of the input parameter, move on to the function logic of createElement.

CreateElement (createElement)

We’ve read the createElement source code down to each line, but we’ll look at the logical level of createElement’s task flow. This process can be summarized as the following flow chart:

This flowchart may shatter the illusion of createElement. In a real-world interview scenario, many candidates tend to exaggerate createElement’s “work” due to their lack of knowledge of the source code. But as you can see, createElement doesn’t have any complicated logic involving algorithms or the real DOM. Every step of createElement is just formatting the data.

To put it more bluntly, createElement acts as a “converter,” a data-processing layer, between the developer and the ReactElement call. It can take relatively simple parameters from the developer, format them as ReactElement expects, and create elements by calling ReactElement. The whole process is shown below:

As it turns out, createElement is simply a “parameter mediation.” At this point, our attention naturally focused on ReactElement, then to build on the success of ReactElement source code!

(4) Out of the interpretation: the first knowledge of virtual DOM

As analyzed above, createElement returns a call to ReactElement at the end. ReactElement = ReactElement = ReactElement

const ReactElement = function(type, key, ref, self, source, owner, {const element = {// REACT_ELEMENT_TYPE is a constant that identifies the object as a ReactElement $$typeof: REACT_ELEMENT_TYPE, // Built-in attribute assignment type: type, key: key, ref: ref, props: props, // Record the component that created the element _owner: owner,}; // if (__DEV__) {return element; // If (__DEV__) {return element; };Copy the code

The code for ReactElement is surprisingly short, and logically ReactElement does only one thing:create“Or, to be more precise,”The assembly“: the ReactElementThe parameters passed in follow certain specifications, “assembles” it into the Element object and returns it to the React.createElement, which ultimately passes it back to the developer. The whole process is shown below:

If you want to verify this, try printing the JSX part of the App component in our example:

const AppJSX = (<div className="App">
  <h1 className="title">I am the title</h1>
  <p className="content">I am the content</p>
</div>)
console.log(AppJSX)
Copy the code

You can see that it is indeed a standard instance of the ReactElement object, as shown below (in production) :

This instance of the ReactElement object is essentially a description of the DOM in the form of a JavaScript object, known as the “virtual DOM” (specifically, a node in the virtual DOM). The virtual DOM will be explored extensively in a follow-up column, “Module 2: Core Principles,” but you’ll only need to be able to combine the source code to get a sense of it.

Since it’s a “virtual DOM,” that means there’s still some distance between the actual DOM rendered to the page, and that “distance” is filled in by the beloved reactdom.render method.

A call to the React. Render function is included in every React project entry file. Let’s look at the entry rules for the reactdom.render method:

Reactdom.render (// The element to be ReactElement) element, // the target container to which the element is attached (a real DOM), // the callback function, optional arguments, Can be used to handle logic after rendering (callback).Copy the code

The reactdom. render method takes three arguments, the second of which is an actual DOM node. The actual DOM node acts as the “container” into which the React element is eventually rendered. For example, the App component in the example would correspond to the render call like this:

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Copy the code

Note that the real DOM must exist. For example, in the index.html of the App component, the root node with id root has been preset in advance:

<body>
    <div id="root"></div>
</body>
Copy the code

This means that the DOM node with the ID root will become a container for the app component, which will eventually be mounted as a child of root, as shown in the figure below

Above, for the three questions mentioned at the beginning of the article, through the knowledge exploration throughout the whole article, WE believe that we can find answers to the remaining doubts about the three questions.

3. Final conclusion:

Of course, all the knowledge mentioned above is just an introduction for us to delve deeper into react knowledge system and its operation mechanism. The next step is to explore how a React component lives its life and how it “updates” itself in time.

Learning the source (the article reprinted from) : kaiwu.lagou.com/course/cour…