Preparation stage

Create a project

  • throughcreate-react-app easy_reactScaffolding creates a project
  • Clean up thesrcThe catalog, we only have one hereindex.jsCan be
  • Modify theindex.jsThe following
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
const style = {
  color: 'red'.background: 'yellow'.fontSize:'20px'
}
ReactDOM.render(
  <h1 id={'gu_yan'} className={'gu-yan'} style={style}>
    Guyan
  </h1>.document.getElementById('root'));
Copy the code

Start the project

  • performyarn startThe page looks like this

The analysis phase

  • willindex.jsCode copy tobabel, the effect is as follows
  • Analysis of the above
    • Comparing the code before and after, we see the following changes
    /** * 

    * Guyan *

    , document.getElementById('root')); * /
    CreateElement ()"h1", { id: 'gu_yan'.className: 'gu-yan'.style: style }, "Guyan") Copy the code
  • willindex.jsThe file is modified as follows. The page is found unchanged. The console prints the result as shown in the following figure
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
const style = {
  color: 'red'.background: 'yellow'.fontSize: '20px'
};
const element = React.createElement("h1", {
  id: 'gu_yan'.className: 'gu-yan'.style: style
}, "Guyan")
console.log(element)
ReactDOM.render(element, document.getElementById('root'));
Copy the code

  • As shown in the figure aboveReact.createElement()The result of the execution is an object, which we call virtualDOMHere we can sum up the virtualDOMThe origin of the
    • 【 1 】 inwebpackIt’s called when you packbabel-loaderThat will beJSXThe syntax escape isReact.createElement(...)In the form of
    • 【 2 】React.createElementThe execution returns an object, which is virtualDOM
  • parsingReact.createElementThe execution process of
    • [1] Collect attribute objects and handle special attributes such aschildren.key.ref; This article only illustrates exampleschildren
      • [1-1] Create onepropsobject
      • [1-2] hang each attribute in the second parameter object passed inpropsIs the value of the second argument object relative to
      • [1-3]propsHang achildrenProperty, and the value is the third parameter passed in
        • Note:childrenThe value is either a string or an array. If you executeReact.createElementWhen the parameter passed is greater than 3, thenchildrenThe value of is an array of all attributes except the first two
    • [2] will be incomingtypeAnd the collected property object is passed in as a parameterReactElementTo execute (reactElement(type,props))
    • [3]ReactElementExecute to create anewElementobject
    • [4]newElementHang a? typeofProperty, here we uniformly assign its value toSymbol(react.element)
    • [5]newElementHang atypeProperty with the value passed intype
    • [6]newElementHang apropsProperty with the value passed inprops
    • [7] ReturnnewElement(virtualDOM)
  • parsingReactDom.renderThe execution process of
    • [1] Judge the incoming virtualDOMThe type of
      • [1.1] Plain text type, the first parameter may bestringornumber, a real text node is created directly
      • [1.2] OrdinaryhtmlTag components, such as<div></div>Of the first argument objecttypeA property is astringType to create a real oneDOMNode and take the first parameterpropsSome common properties in the property are mounted to the realDOMNode, and for some special properties likechildrenFor details, see belowThe implementation phase
      • [1.3] Function components (function Component) of the first argument objecttypeA property is afunctionType,typeExecutes the object passed the first argumentprops
      • [1.4] Class Components (class Component) of the first argument objecttypeThere’s one on the propertyisReactComponentProperties,new type(props)Create an instance and let the instance’srenderMethods to perform
    • [2] Insert the created real node into the parent node

The implementation phase

react.js

// _react.js

    class Component {
        static isReactComponent = true;
        constructor(props){
            this.props = props; }}function ReactElement(type,props){
        const virtual_dom = {};
        virtual_dom.?typeof = Symbol.for('react.element');
        virtual_dom.type = type;
        virtual_dom.props = props;
        return virtual_dom;
    }

    function createElement(type,config,children){
        const props = {};
        for (const propName in config){
            if(config.hasOwnProperty(propName)){ props[propName] = config[propName]; }}const childrenLength = arguments.length - 2;
        if (childrenLength === 1){
            props.children = children;
        }else if (childrenLength > 2){
            props.children = Array.from(arguments).slice(2);
        }
        return ReactElement(type,props);
    }
    
    export default {createElement,Component}
Copy the code

react-dom.js

// _react_dom.js
    
    function render(virtual_dom,parent_node){
        if (typeof virtual_dom ==='string' || typeof virtual_dom === 'number') {/** * handles direct rendering of text nodes, such as reactdom.render ('guYan', document.getelementByid ('root')); * /
         return parent_node.appendChild(document.createTextNode(virtual_dom));
        }
        
        if (virtual_dom.type.isReactComponent){
         /**
         *处理直接渲染Class Component的情况
         */
            virtual_dom = new virtual_dom.type(virtual_dom.props).render();
            render(virtual_dom,parent_node);
        }
        
        if (typeof virtual_dom.type === 'function') {/**
         *处理直接渲染function Component的情况
         */
            virtual_dom = virtual_dom.type(virtual_dom.props);
            render(virtual_dom,parent_node);
        }
        let {type , props} = virtual_dom;
        let real_dom = document.createElement(type); // Create a real node based on type
        for (const propName in props){ // handle the props
            if(props.hasOwnProperty(propName)){
                const prop =  props[propName];
                if(propName === 'className'){
                    real_dom.className = prop;
                }else if (propName === 'style') {let cssText = Object.keys(prop).map(attr= >(`${attr.replace(/([A-Z])/g.function() {return ` -The ${arguments[1].toLowerCase()}`
                    })} :${prop[attr]}`)).join('; ');
                    real_dom.style.cssText = cssText;
                }else if (propName === 'children') {/** *children may be a string or an array, if it is a string converted to an array, and then recursively calls render, note that the parent node passed in is real_dom */ that we created
                    let childArr = Array.isArray(prop) ? prop : [prop];
                    childArr.forEach(child= >render(child,real_dom));
                }else{ real_dom.setAttribute(propName,prop); }}}return parent_node.appendChild(real_dom);
    }
Copy the code

Write in the last

  • Everyday use of functional components is recommended
    • 1. Easy to use
    • 2. Save memory
    • 3. Improve performance
  • In this paper, the principle is explained only at the surface level. Without in-depth analysis, how to error also hope to teach. Thank you very much!