“This article has participated in the good article call order activity, click to see: back end, big front end double track submission, 20,000 yuan prize pool for you to challenge!”

preface

At present, most of the surrounding front-end is using Vue, but I don’t know much about Vue. Think back to the front end that I had been working on for almost 3-5 years before this. Went from Jqeury to Angularjs to React, put down the front end and then did some Android development, and is now an AI engineer. It’s probably because javascript is the language that got me interested in programming and has been with me for many difficult times, so THERE’s always something sentimental about javascript.

I want to write a relatively complete and comprehensive share about React, and then pick up the copy of myself before to write a React, and continue to write a React, which can be used to write a driverless interface.

I may not be able to list all the content at one time, so to make it clear, so the share will continue to be updated, and the previous content will be updated as I continue to deepen the React

What is the React

React is a JavaScript library for building user interfaces. Officials use three phrases to characterize React: declarative, componentized, and one-time development. Here, we will not quote the official introduction of the three features, but explain in our own words what they are and why the official use these three features to mark React.

declarative

What is declarative? What’s in it for him? Here’s one that you’re familiar with and maybe you don’t realize is a declarative language, but when we start learning about front ends, the first contact is usually, or always, HTML, the hypertext markup language, which is a declarative language. You must be very quick to learn HTML, a simple look at HTML to define the structure of the page. This suggests that declarative language is much more understandable and friendly to us humans. Further, if you know HTML at all, you’ll probably have an idea of what a page looks like when it’s defined in HTML, without the need for a browser to generate the page from HTML code. This is the benefit of declarative languages. Declarative languages are more reliable, easier to debug, and more readable, which means easier to maintain.

componentization

Various design patterns. One of the goals of design patterns is to reduce code redundancy. It’s not just about reducing the workload, it’s not necessarily about reducing the workload, it’s about maintaining it, and I’m not going to go into that, because if you’ve worked on a large project, you know what happens when you copy code from a project. More and more, Web projects are taking responsibility for componentizing pages, componentizing functionality, and providing reuse of code and logic.

Each component is highly cohesive, with low coupling between components. The components communicate with each other and exchange information in a unified manner.

One learning, cross-platform writing

This is a dream not just for Facebook, but for many big companies. Google does this with Their Flutter. They usually compare Their Flutter to React. I wrote a few lines of code the year before last, and I felt like I was writing React. Most new frameworks and languages embrace the future and don’t forget the past, for example this is so successful. So why is React able to do this? This is because of vDom, and this is a little personal understanding, Java is cross-platform only because of bytecode and virtual machines. React cross-platform basically abstracts the page representation to VDom, VDom as the view description, and then just implements the renderer on different platforms.

JSX

JSX is a syntax extension to JavaScript that has the benefit of being more intuitive.

const element = <h1 title="foo">hello</h1>
Copy the code

Babel then converts JSX to JS code and the HTML tag to createElement to create the element.

const element = React.createElement(
    "h1",
    {title: "foo"},
    "Hello"
)
Copy the code

Virtual DOM and diff algorithm

Virtual DOM and Diff algorithm of React are very important core features of React. The concept of virtual DOM was first proposed in React. Therefore, this part of the source code is also very complex, understanding the principle of this knowledge is very necessary for a deeper grasp of React. In version 16, fiber corresponds to a virtual DOM. This share first reserve, then estimate need to take out a share to specifically say this piece of content.

fiber

A process is the unit of memory that the system allocates to an application. A thread is the smallest unit of CPU scheduling. A process can contain multiple threads. That’s why it’s called fiber.

Run javascript and render page threads

The problem stems from the design of javascript, which is single-threaded and non-blocking. So the javascript code runs and the page is rendered on one thread. Asynchrony, also known as non-blocking, is achieved by means of the event loop mechanism, which has been described in detail before, and will not be introduced too much here.

On this thread, there are a number of things that need to be done, such as event handling, timers, launch frame events, and rAF to start rendering the page. Rendering the page is divided into two steps: layout and drawing. Usually render priority action actually lower than these before treatment, optional render movement is after these tasks, but the browser is very smart, because usually we display are 60 HZ refresh 60 times a second screen, so that is about 16.6 milliseconds will refresh the screen, when any other quickly implemented at random, The browser does not go away from performing the render page action, but keeps updating the page at a rate of about 16.6 milliseconds. If the javascript code takes too long to execute and stays on the main thread, it will get stuck.

The original Stack Reconciler looked like a recursively executed function, and the process of calling a child reconciler from a parent is a recursively executed process, which is why it is called a stack Reconciler. When we call setState, React iterates from the root node to find all the differences, and for a very large DOM tree, this recursive iterating process can take a very long time. During this time, any interaction and rendering is blocked, giving the user a “crash” feeling.

You can write a mini version of your own React. You can also write a mini version of your own React. You can also write a mini version of your own React. Which introduced the hooks, filter and concurrent mode implementation, sparrow is small, all five organs. I recommend you to write it yourself. On the one hand, to understand the beauty of React design, on the other hand, it will give you some inspiration for your own development projects.

<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <title>Document</title>
</head>
<body>
    <div id="root"></div>
    <script src="index.js"></script>
</body>
</html>
Copy the code

< div id=”root”>
const element = {
    type:"h1".props: {title:"foo".children:"Hello"}}const container = document.getElementById("root");
// ReactDOM.render(element, container)


const node = document.createElement(element.type);
node["title"] = element.props.title;

const text = document.createTextNode("");
text["nodeValue"] = element.props.children;

node.append(text);
container.append(node);
Copy the code

Implement the createElement function

const element = (
    <div id="foo">
        <a>bar</a>
        <b/>
    </div>
)

const container = document.getElementById("root");
ReactDOM.render(element,container)
Copy the code

From the React code above we can see the advantages of declarative languages, which are very readable.

const element = React.createElement(
    "div",
    {id:"foo"},
    React.createElement("a".null."bar"),
    React.createElement("b"))const container = document.getElementById("root");
ReactDOM.render(element,container);
Copy the code

React. CreateElement takes three arguments. The first argument is the node type, a string type. The second argument is an object type, passing in the node’s property name and value in the form of a key-value pair. The JSX syntax is converted by Babel to the createElement method

function createElement(type, props, ... children){
    return{
        type,
        props: {... props, children }, } } miniReact = { createElement }const element = miniReact.createElement(
    "div",
    {id:"foo"},
    miniReact.createElement("a".null."bar"),
    miniReact.createElement("b"))Copy the code

MiniReact is the name of the frame we want to write, then replace all previous React names with miniReact, then createElement.

function createElement(type, props, ... children){
    return{
        type,
        props: {... props,children: children.map(child= > 
              typeof child === "object"
                ? child
                : createTextElement(child)  
                
            ),
        },
    }
}

function createTextElement(text){
    return {
        type: "TEXT_ELEMENT".props: {nodeValue: text,
            children: []}}}Copy the code

We use the spread operator for props. We also use the spread operator for children, a new ES6 feature. Note that children’s prop is always an array.

function createTextElement(text){
    return {
        type: "TEXT_ELEMENT".props: {nodeValue: text,
            children: []}}}Copy the code

Render function

The Render method here is the React commit phase, which renders the updated virtual DOM to the interface.

function render(element, container){

}

miniReact = {
    createElement,
    render
}
Copy the code

Render’s job is to read the element, convert it to an HTML Dom element, and then add it to the container node. React uses different rendering engines to render VMOD on different devices to make it cross-platform.


function render(element, container){
    console.log("render phase")
    const dom = document.createElement(element.type);
    container.appendChild(dom);
}

Copy the code

Children of recursive elements, and when you look at recursion you should think about memory consumption and thread consumption, and you’ve used dynamic programming to solve recursion problems by caching or substitution.

function render(element, container){
    // console.log("render phase")
    const dom = document.createElement(element.type);
    element.props.children.forEach(child= > 
        render(child,dom)
    )
    container.appendChild(dom);
}
Copy the code
function render(element, container){
    // console.log("render phase")
    const dom = element.type == "TEXT_ELEMENT"
        ? document.createTextNode("")
        : document.createElement(element.type);
    element.props.children.forEach(child= > 
        render(child,dom)
    )
    container.appendChild(dom);
}
Copy the code

Text nodes are processed separately when Dom elements are created, so a little special processing is done here. Call the createTextNode method after determining that the virtual node is TEXT_ELEMENT to generate the node.

function render(element, container){
    // console.log("render phase")
    const dom = element.type == "TEXT_ELEMENT"
        ? document.createTextNode("")
        : document.createElement(element.type);

    const isProperty = key= >key ! = ="children"
    Object.keys(element.props)
        .filter(isProperty)
        .forEach(name= > {
            dom[name] = element.props[name]
        })
    element.props.children.forEach(child= > 
        render(child,dom)
    )
    container.appendChild(dom);
}
Copy the code

I’ll share that for now, and then I’ll share the Concurrent mode implementation and how the Fiber algorithm solves this problem.