React: v15.0.0

This article explains how components are compiled and how reactdom.render is rendered.


Babel compilation

Babel compiles React JSX to JavaScript.

Babel JSX code:

Each tag creation calls React. CreateElement.


Two data structures in the source code

Throughout the source code, two common data structures help to quickly read the source code.

ReactElement

The structure is as follows:

{?typeof  // ReactElement identifier
  type      / / component
  key
  ref
  props     // Component properties and children
}
Copy the code

Is the return value of react. createElement.

ReactComponent

The name ReactComponent is a bit strange.

The structure is as follows:

{
  _currentElement    // ReactElement.// The method on the prototype chain
  mountComponent,    // Component first load call
  updateComponent,   // Component update call
  unmountComponent,  // Component unload calls
}
Copy the code

Is the instance type of ReactCompositeComponent. The other three constructors, ReactDOMComponent, ReactDOMTextComponent, and ReactEmptyComponent, have similar instance structures.


React.createElement

React. The createElement method of actual execution is ReactElement. The createElement method (directory: / element/SRC/isomorphic/classic ReactElement. Js).

ReactElement. The createElement method receives the three parameters, return ReactElement structure.

  • type: string | Component
  • Config: indicates the attribute on the label
  • . Children: Sets of children elements

Focus on type and props.

And then look at the ReactElement method, it’s just doing the assignment.

To sum up, our code compiled looks like this:

class C extends React.Component {
  render() {
    return {
      type: "div".props: {
        children: this.props.value, }, }; }}class App extends React.Component {
  render() {
    return {
      type: "div".props: {
        children: [{type: "span".props: {
              children: "aaapppppp",}},"123",
          {
            type: C,
            props: {
              value: "ccc",},},]},}; } } ReactDOM.render( {type: App,
    props: {},},document.getElementById("root"));Copy the code


ReactDOM.render

Take a look at the ReactDOM. Render source code execution process




instantiateReactComponent

In _renderNewRootComponent approach, called instantiateReactComponent (directory: SRC/renderers/Shared/reconciler instantiateReactComponent. Js), generates an instance of the structure is similar to ReactComponent.

InstantiateReactComponent parameter is the node, the node ReactElement is one of the format.

Depending on the type of node & Node. type, different methods are executed to generate instances

  • ReactCompositeComponent
  • ReactDOMComponent
  • ReactDOMTextComponent
  • ReactEmptyComponent

Simplify the following

var instantiateReactComponent = function (node) {
  if (node === null || node === false) {
    return new ReactEmptyComponent(node);
  } else if (typeof node === 'object') {
    if (node.type === 'string') {
      return new ReactDOMComponent(node);
    } else {
      return newReactCompositeComponent(node); }}else if (typeof node === 'string' || typeof node === 'number') {
    return newReactDOMTextComponent(node); }}Copy the code

Objects instantiated in all four ways are basically similar

var instance = {
  _currentElement: node,
  _rootNodeID: null. } instance.__proto__ = { mountComponent, updateComponent, unmountComponent, }Copy the code

The four mountComponents are simplified as follows

ReactCompositeComponent

Source directory: SRC/renderers/Shared/reconciler ReactCompositeComponent. Js.

mountComponent: function () {
  // Create an instance of the current component
  this._instance = new this._currentElement.type();

  // Call the component's render method to get the component's renderedElement
  renderedElement = this._instance.render();

  / / call instantiateReactComponent, get the instantiation ReactComponent renderedElement
  this._renderedComponent = instantiateReactComponent(renderedElement);

  / / call ReactComponent mountComponent
  return this._renderedComponent.mountComponent();
}
Copy the code

ReactDOMComponent

Source directory: dom/Shared/SRC/renderers/ReactDOMComponent. Js.

In react source code, use ownerDocument and DOMLazyTree to create and store nodes before inserting containers.

mountComponent: function () {
  var { type, props } = this._currentElement;

  // Create dom source code using ownerDocument
  var element = document.createElement(type);

  // Recursive children (DOMLazyTree)
  if (props.children) {
    var childrenMarkups = props.children.map(function (node) {
      var instance = instantiateReactComponent(node);
      return instance.mountComponent();
    })

    element.appendChild(childrenMarkups)
  }

  return element;
}
Copy the code

ReactDOMTextComponent

Source directory: dom/Shared/SRC/renderers/ReactDOMTextComponent. Js.

mountComponent: function () {
  return this._currentElement;
}
Copy the code

ReactEmptyComponent

Source directory: SRC/renderers/Shared/reconciler ReactEmptyComponent. Js.

mountComponent: function () {
  return null;
}
Copy the code


ReactDOM. Render simplified

Simplified as follows:

ReactDOM.render = function (nextElement, container) {
  // Add a shell
  var nextWrappedElement = ReactElement(
    TopLevelWrapper,
    null.null.null.null.null,
    nextElement
  );

  // Instantiate ReactElement
  var componentInstance = instantiateReactComponent(nextElement);

  // Generate HTML recursively
  var markup = componentInstance.mountComponent;

  // Insert the real DOM
  container.innerHTML = markup;
}
Copy the code


conclusion

  1. Babel compiles the JSX syntax into the react. createElement form.
  2. The source code uses two important data structures
    • ReactElement
    • ReactComponent
  3. React.createElement processes the component we wrote into a ReactElement structure.
  4. Reactdom. render passes in ReactElement and container as follows
    • On the ReactElement layer, a new ReactElement is generated
    • Instantiation ReactElement: var instance = instantiateReactComponent (ReactElement)
    • Markup: var markup = instance.mountComponent()
    • Insert markup into the container: container. InnerHTML = markup


whosmeya.com