How React Core Works

1.1. Virtual DOM

FAQ: What is react virtual dom? Tell me about the diff algorithm?

When you get a question, what is the general answer? Why? How to do? Then go with this idea!

what

Use JavaScript objects to represent DOM information and structure, and when the state changes, re-render this JavaScript object structure. This JavaScript object is called virtual dom;

why

DOM operations are very slow, and slight operations may cause page re-layout, which is very performance-intensive. Compared to DOM objects, js objects are faster and simpler to process. By comparing the difference between the old and new vdom s through the diff algorithm, dom operations can be performed in batches and minimized, thereby improving performance.

where

Views are described in JSX syntax in React, and after they are translated by babel-loader, they become in the form of React.createElement(...), which will generate vdom to describe the real dom. If the state changes in the future, vdom will make corresponding changes, and then compare the difference between the new and old vdom through the diff algorithm to make the final dom operation.

Speaking of JSX here, let’s talk about it by the way:

What is JSX
syntactic sugar, React use JSX to replace the conventional JavaScript. 

JSX is a look like XML of JavaScript Syntax expansion.
React practical video explanation: into learning
Why do you need JSX
Development efficiency: use JSX Writing templates is easy and fast.

effectiveness: JSX compiles to JavaScript Code-post optimizations are made to execute faster.

Type Safety: Errors can be found during compilation.
React 16 Principles
babel-loader will be precompiled JSX for React.createElement(...)
React 17 Principles
React 17 middle JSX conversion will not JSX convert to React.createElement´╝îbut automatically from React of package Introduce a new entry function in and call it. In addition, this upgrade will not change JSX grammar, old JSX Conversions will also continue to work.
Similarities and differences with vue

The design of virtual dom+jsx in react was there from the beginning, and vue only appeared in the evolution process, and appeared after version 2.0.

jsx is originally a js extension, and the escaping process is much simpler and more direct; the process of compiling template into render function by vue requires a complex compiler to convert the string-ast-js function string

1.2, render, Component basic core api

render

ReactDOM.render(element, container[, callback]);

When called for the first time, all DOM elements in the container node will be replaced, and subsequent calls will use React's DOM diffing algorithm for efficient updates.

If an optional callback function is provided, the callback will be executed after the component is rendered or updated.

Node type

1,text node
2,html label node
3,functional component
4,class component
...
functional component
// start with bigger letters
function Welcome(props) {
    return <h1>Hello, {props.name}</h1>
}
class component

React components can be defined in the form of classes or functions. To define class components, you need to inherit React.Component or React.PureComponent:

class Welcome extends React.Component {
    render() {
        return <h1>Hello, {this.props.name}</h1>
    }
}

1.3, handwritten short version of myreact

Implement initial rendering of native label nodes, text nodes, function components and class components

First create a React project with Create React App, install dependencies and run;

Then add this code to src/index.js to check the version number and make sure you have version 17

console.log("version", React.version);

It is precisely because in React17 that React will automatically replace JSX with js objects, so we mainly need to comment out src/index.js:

// import React from "react";
// import ReactDOM from "react-dom";

Then create a myreact folder under src and create a react-dome.js inside

// vnode virtual dom object
// node real dom node

// ! First render
function render(vnode, container) {
  // react17 can automatically turn virtual dom
  console.log("vnode", vnode);
  // vnode->node
  const node = createNode(vnode);

  // node->container
  container.appendChild(node);
}

// create node
function createNode(vnode) {
  let node;
  const {type} = vnode;

  // todo creates different node nodes according to the component type

  if (typeof type === "string") { // native label node
    node = updateHostComponent(vnode);
  } else if (typeof type == "function") { // Functional components Let’s distinguish between class components and functional components again
    node = type.prototype.isReactComponent  
      ? updateClassComponent(vnode)
      : updateFunctionComponent(vnode);
  } else { // text node
    node = updateTextComponent(vnode);
  }

  return node;
}

// native label node
function updateHostComponent(vnode) {
  const {type, props} = vnode;
  const node = document.createElement(type);

  console.log('document.createElement', node)

  // update node section
  updateNode(node, props); // Attributes

  reconcileChildren(node, props.children); // traverse children

  return node;
}

// update properties
function updateNode(node, nextVal) {
  Object.keys(nextVal)
    .filter((k) => k !== "children") // filter children
    .forEach((k) => (node[k] = nextVal[k])); // Generate properties
}

// text node
function updateTextComponent(vnode) {
  const node = document.createTextNode(vnode);
  return node;
}

// functional component
function updateFunctionComponent(vnode) {
  const {type, props} = vnode;
  // type is a function
  const vvnode = type(props);
  // vvnode->node
  const node = createNode(vvnode);

  return node;
}

// class component
function updateClassComponent(vnode) {
  const {type, props} = vnode;
  // Class components require new 
  const instance = new type(props);

  console.log('instance', instance);

  const vvnode = instance.render();

  console.log('vvnode', vvnode);
  // vvnode->node
  const node = createNode(vvnode);
  return node;
}

// traverse children
function reconcileChildren(parentNode, children) {
  // It is a little different from the source code, but it is also to determine whether it is an array
  const newChildren = Array.isArray(children) ? children : [children];

  for (let i = 0; i < newChildren.length; i++) {
    let child = newChildren[i];
    // vnode
    // vnode->node, node is inserted into parentNode
    render(child, parentNode);
  }
}

export default { render };

Next, create a src/myreact/Component.js file:

// Class components must inherit from Component or PureComponent
function Component(props) {
  // Need to bind this
  this.props = props;
}

// Made a markup of a class component
Component.prototype.isReactComponent = {};

export default Component;

Oh, don't forget to change the contents of the src/index.js file:

// import React from 'react';
// import ReactDOM from 'react-dom';
import ReactDOM from './myreact/react-dom';
import Component from "./myreact/Component";
import './index.css';
// import App from './App';
import reportWebVitals from './reportWebVitals';

class ClassComponent extends Component {
  render() {
    return (
      <div>
        <p>class component-{this.props.name}</p>
      </div>
    );
  }
}

export default ClassComponent;

function FunctionComponent(props) {
  return (
    <div>
      <p>functional component-{props.name}</p>
    </div>
  );
}

const jsx = (
  <div className="myjsx">
    <h1>111111</h1>
    <h2>222222</h2>
    <h3>111111</h3>
    <a href="https://www.baidu.com/">Baidu</a>
    <FunctionComponent name="I am a functional component" />
    <ClassComponent name="I am a class component" />
  </div>
)

// native tags
// text node
// functional component
// class component

ReactDOM.render(
  jsx,
  document.getElementById('root')
);

// console.log("version", React.version); // version 17.0.1

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

The overall code is like this, the specific process will not be explained in detail here, you can take a good look at the code, and you can contact me if you have any questions.

summary

1,React17 middle, React will automatically replace JSX for js object.

2,js object i.e. vdom´╝îit can fully describe dom structure.

3,ReactDOM.render(vdom, container)can vdom convert to dom and append to container middle.

4,In fact, the conversion process needs to go through a diff process.

Tags: React

Posted by grazzman on Wed, 28 Sep 2022 08:12:12 +0930