Virtual DOM

The main idea of Virtual DOM is to simulate the tree structure of DOM and create node data to save mapping DOM information in memory. When view update is needed due to interaction and other factors, the node data should be diff to get the difference results, and then the DOM should be updated in batches at one time. This is like creating a parallel world in memory. Every node and attribute data of the DOM tree in the browser has another version of the Virtual DOM tree in this parallel world. All the complicated and convoluted update logic is processed in the Virtual DOM in the parallel world. Only the final update result is sent to the DOM tree in the browser for execution, thus avoiding the burden of redundant trivial DOM tree operations, thus effectively improving performance.

Virtual DOM in React

React actually emulates the DOM tree structure by creating a JavaScript object (Virtual DOM) using React. CreateElement

<div>
    Virtual DOM
</div>
Copy the code

The converted object looks like this:

The source code parsing

Ps. The following code are simplified after the source code, it looks convenient

How does the createElement method transform the element into the corresponding JS object

React.createElement(
    "div",
    {className: 'test'},
    "1"
)
Copy the code

createElementThe arguments

  • type: can be a type parameterHTMLElements (<div>, etc.)ReactComponent type
  • props:propsThe ginseng
  • children: child elements. All parameters passed from the third argument are child elements

createElementProcessing flow of

  1. Handle the incoming parameter, props

    • willref,keyThis is why child componentspropsIn less thanref,key)
    • will__self,__sourcepropsPeel out of
    var key = null;
    var ref = null;
    var source = null;
    var self = null;
    
    // Props = props = props
    if(props ! = =null) {
        if (props.ref) {
            ref = props.ref
            props.delete(ref);
        }
    
        if (props.key) {
            key = ' ' + props.key;
            props.delete(key);
        }
    
        if(props.__self) {
            self = props.__self;
            props.delete(__self);
        }
    
        if(props.__source) { self = props.__source; props.delete(__source); }}Copy the code
  2. Handle the input, children

    • inpropsObjectchildrenProperty, whose value is the incoming parameterchildren
    • If you have more than onechildrenIf input, it is merged into an array
    // Integrate all child elements into props. Children
    var childrenLength = arguments.length - 2;
    if (childrenLength === 1) {
        // Only one child element
        props.children = children;
    } else if (childrenLength > 1) {
        // Combine multiple child elements into one array
        var childArray = Array(childrenLength);
        for (var i = 0; i < childrenLength; i++) {
            childArray[i] = arguments[i + 2];
        }
        Object.freeze(childArray);
        props.children = childArray;
    }
    Copy the code
  3. Handling defaultProps on class components

    • Component defaultprops
    • ifpropsIf there is no corresponding attribute on thedefaultPropsAttribute value assigned toprops
    // Assigns the props to defaultProps
     if (type && type.defaultProps) {
         for (let propName in type.defaultProps) {
             if (props[propName] === undefined) { props[propName] = defaultProps[propName]; }}}Copy the code
  4. Integrate into JS objects

const REACT_ELEMENT_TYPE = Symbol.for('react.element');

let ReactCurrentOwner = {
    current: null,}function createElement(type, props, children) {
    / / processing props./ / deal with children./ / defaultProps processing.// Integrate into js objects
    const element = {
        $$typeof: REACT_ELEMENT_TYPE,
        type: type,
        key: key,
        ref: ref,
        props: props,
        _owner: ReactCurrentOwner.current,   // Create an object for the current component. The default value is NULL
    };

    element._store = {};

    Object.defineProperty(element._store, 'validated', {
        configurable: false.enumerable: false.writable: true.value: true    // If the React object is valid, the value will be true. If the React object is valid, the value will be true
    });

    Object.defineProperty(element, '_self', {
        configurable: false.enumerable: false.writable: false.value: self
    }); // Two elements created in two different places should be considered
    // equal for testing purposes and therefore we hide it from enumeration.

    Object.defineProperty(element, '_source', {
        configurable: false.enumerable: false.writable: false.value: source
    });

    if (Object.freeze) {
        Object.freeze(element.props);
        Object.freeze(element);
    }

    return element;
}
Copy the code
  1. The last object to be rendered

reference

  • Virtual DOM and kernel
  • coordinate
  • Explore the Virtual DOM
  • React source parsing (1): component implementation and mounting