This section is a collection of implementation notes for the Stack Reconciler program.

This article is technical, with a deep understanding of the React public API and how it is divided into core, renderer and Reconciler programs. If you’re not familiar with the React codebase, read the overview of the codebase first.

It also assumes that you understand the differences between instances and elements of the React component.

The Stack Reconciler is used in version 15 and earlier. Its code in the SRC/renderers/Shared/stack/reconciler.

Video: Building React from scratch

Paul O ‘Shannessy talked about building React from scratch, which largely inspired this document.

This document and his talk are simplifications of the actual code base, so you can gain a better understanding by familiarizing yourself with them.

An overview of the

There is no public API for the Reconciler itself. Renderers like React DOM and React Native use it to effectively update the user interface based on user-written React components.

Mounting as a recursive process

Let’s consider mounting a component for the first time:

ReactDOM.render(<App />, rootEl);
Copy the code

The React DOM passes the
to the Reconciler. Remember that
is a React element, which is a description of what to render. You can think of it as an ordinary object:

console.log(<App />);
// { type: App, props: {} }
Copy the code

The mediator checks whether the App is a class or a function (see how to know if it’s a function or a class for this implementation).

If App is a function, the mediator calls App(props) to get the render element.

If App is a class, the mediator instantiates the App with the new App(props), calls the componentWillMount lifecycle method, and then calls the Render method to get the rendered elements.

Either way, the mediator will know what elements the App has “rendered to.”

The process is recursive. Your App might render
,
might render , and so on. The mediator will recursively “drill down” the user-defined components as it learns what each component renders.

Think of this process as pseudocode:

function isClass(type) {
  // The class below react.componenthas this tag
  return (
    Boolean(type.prototype) &&
    Boolean(type.prototype.isReactComponent)
  );
}

// This function accepts a React element (e.g. 
      )
// And returns a DOM or native node with the tree already mounted
function mount(element) {
  var type = element.type;
  var props = element.props;

  // We will determine the type of render element
  // The function is called directly
  // The class calls render() after instantiation.
  var renderedElement;
  if (isClass(type)) {
    / / class components
    var publicInstance = new type(props);
    / / set the props
    publicInstance.props = props;
    // Call the lifecycle method if necessary
    if (publicInstance.componentWillMount) {
      publicInstance.componentWillMount();
    }
    // Get rendered elements by calling render()
    renderedElement = publicInstance.render();
  } else {
    // Function components
    renderedElement = type(props);
  }

  // The process is recursive because one component may return an element of the same type as another component
  return mount(renderedElement);
    
  // Note: this implementation is incomplete and will repeat indefinitely
  // It only handles elements like 
       or .
  // It does not yet handle elements like 
      
or

.
} var rootEl = document.getElementById('root'); var node = mount(<App />); rootEl.appendChild(node); Copy the code

Note: This is really just pseudocode, and it doesn’t look like the real implementation. It also causes a stack overflow, because we haven’t discussed when to stop recursion.

Let’s review some key ideas from the example above:

  • React Elements is just a pure object that describes the type of component (e.g.App) and his props.
  • User-defined components (e.g.App) can be functions or classes, but they both render these elements.
  • Mounting is a recursive process that determines whether a given React element (e.g<App />) to create a DOM or Native tree.

Mounting The computer (Host) element

This process is useless if we don’t have something on the screen.

In addition to user-defined (” composite “) components, React elements can also represent platform-specific (” computer “) components. For example, Button might return

from its Render method.

If element’s type attribute is a string, we think we’re dealing with a computer element:

console.log(<div />);
// { type: 'div', props: {} }
Copy the code

There is no user-defined code associated with the computer element.

When the coordinator encounters these computer elements, it makes the renderer responsible for mounting them. For example, React DOM creates a DOM node.

If a computer element has child nodes, the coordinator mounts them recursively with the same algorithm as above. It doesn’t matter whether the child node is a computer element (

< HR />

) or a user-generated component (

).

The DOM node generated by the child component is attached to the parent DOM node and the complete DOM structure is recursively assembled.

Note: The mediator itself is DOM independent. The exact result of mounting the mounting(sometimes called the “mount image” in source code) depends on the renderer, and can be a React DOM node, a string, or a React Native view.

If we were to extend the code to handle computer elements, it would look like this:

function isClass(type) {
  // The react.componentclass inherits a tag isReactComponent
  return (
    Boolean(type.prototype) &&
    Boolean(type.prototype.isReactComponent)
  );
}

// This function only handles composite elements
// Such as 
      , , but not 
      
function mountComposite(element) { var type = element.type; var props = element.props; var renderedElement; if (isClass(type)) { // If the component is a class, instantiate it var publicInstance = new type(props); / / set the props publicInstance.props = props; // Call lifecycle methods when necessary if (publicInstance.componentWillMount) { publicInstance.componentWillMount(); } renderedElement = publicInstance.render(); } else if (typeof type === 'function') { // Component is a function renderedElement = type(props); } // This is recursive // But when the element is the host (e.g.
) instead of the compound (e.g. ), we end up with recursion:
return mount(renderedElement); } // This function only deals with computer elements For example, it handles
and

, but not .
function mountHost(element) { var type = element.type; var props = element.props; var children = props.children || []; if (!Array.isArray(children)) { children = [children]; } children = children.filter(Boolean); // This code should not be in the coordinator. // Different renderers may initialize nodes differently. // For example, React Native will create iOS or Android views. var node = document.createElement(type); Object.keys(props).forEach(propName= > { if(propName ! = ='children') { node.setAttribute(propName, props[propName]); }});// Install the child element children.forEach(childElement= > { // The child can be a computer element (such as
) or a composite component (such as ).
// We all mount recursively var childNode = mount(childElement); // The following one is also platform-specific // It will be handled by different renderers, but this is just an assumption that it is a DOM renderer node.appendChild(childNode); }); // Returns the DOM node as the result of the installation // This is where the recursion ends return node; } function mount(element) { var type = element.type; if (typeof type === 'function') { // User-defined components (composite components) return mountComposite(element); } else if (typeof type === 'string') { // Computer components (e.g.
)
returnmountHost(element); }}var rootEl = document.getElementById('root'); var node = mount(<App />); rootEl.appendChild(node); Copy the code

This is effective, but still far from the way the coordinator actually operates. The key missing piece is support for updates.

Introducing Internal Examples

The key feature of React is that you can re-render everything; it doesn’t recreate the DOM or reset the state.

ReactDOM.render(<App />, rootEl); // The existing DOM should be reused: reactdom.render (<App />, rootEl);
Copy the code

However, our implementation above only knows how to mount the initial tree. It cannot update it because it does not store all the necessary information, such as all publicInstances, or which DOM nodes correspond to which components.

The stack coordinator code base solves this problem by making the mount function a method above a class. But there are some drawbacks to this approach, and we’re going in the opposite direction in our ongoing coordination rewrite task (Author: Fiber is out so far). But that’s how it works now.

Instead of the separate mountHost and mountComposite functions, we will create two classes: DOMComponent and CompositeComponent.

Both classes have a constructor that accepts elements and a mount() method that returns installed nodes. We’ll replace the top-level mount() function with a factory that instantiates the class:

function instantiateComponent(element) {
  var type = element.type;
  if (typeof type === 'function') {
    // User-defined component
    return new CompositeComponent(element);
  } else if (typeof type === 'string') {
    // Platform-specific components, such as computer components (
      
)
return newDOMComponent(element); }}Copy the code

First, let’s consider the CompositeComponent implementation:

class CompositeComponent {
  constructor(element) {
    this.currentElement = element;
    this.renderedComponent = null;
    this.publicInstance = null;
  }

  getPublicInstance() {
    // For composite components, expose instances of the class
    return this.publicInstance;
  }

  mount() {
    var element = this.currentElement;
    var type = element.type;
    var props = element.props;

    var publicInstance;
    var renderedElement;
    if (isClass(type)) {
      // Component class
      publicInstance = new type(props);
      // Set the props
      publicInstance.props = props;
      // Call the lifecycle if necessary
      if (publicInstance.componentWillMount) {
        publicInstance.componentWillMount();
      }
      renderedElement = publicInstance.render();
    } else if (typeof type === 'function') {
      // Component function
      publicInstance = null;
      renderedElement = type(props);
    }

    // Save the public instance
    this.publicInstance = publicInstance;

    // Instantiate the inner instance of the child according to the element
    // It will be DOMComponent, e.g. 
      
,

CompositeComponent, e.g. , var renderedComponent = instantiateComponent(renderedElement); this.renderedComponent = renderedComponent; // Mount the rendered output returnrenderedComponent.mount(); }}Copy the code

This and our previous mountComposite () implementation is no different, but now we can store some information, such as this. CurrentElement, enclosing renderedComponent and enclosing publicInstance, used during the update.

Note that the CompositeComponent instance is different from the user-provided instance of Element.type. CompositeComponent is the implementation details of our CompositeComponent that are never made public to users. The CompositeComponent creates an instance of the user-defined class that we read from Element. type.

To avoid confusion, we call the CompositeComponent and DOMComponent instances “internal instances.” They exist, so we can relate some long-standing data to them. Only the renderer and mediator know they exist.

Instead, we call instances of user-defined classes “public instances.” The public instance is the this you see in render() and other component methods.

For the mountHost() method, refactored to the mount() method on the DOMComponent class, which looks like this:

class DOMComponent {
  constructor(element) {
    this.currentElement = element;
    this.renderedChildren = [];
    this.node = null;
  }

  getPublicInstance() {
    // For DOM components, only expose the DOM node.
    return this.node;
  }

  mount() {
    var element = this.currentElement;
    var type = element.type;
    var props = element.props;
    var children = props.children || [];
    if (!Array.isArray(children)) {
      children = [children];
    }

    // Create and save the node
    var node = document.createElement(type);
    this.node = node;

    // Set the attributes
    Object.keys(props).forEach(propName= > {
      if(propName ! = ='children') { node.setAttribute(propName, props[propName]); }});// Create and save the contained child elements
    // Each of these child elements can be a DOMComponent or CompositeComponent
    // These matches are dependent on the return value of the element type (string or function)
    var renderedChildren = children.map(instantiateComponent);
    this.renderedChildren = renderedChildren;

    // Collect DOM nodes they return on mount
    var childNodes = renderedChildren.map(child= > child.mount());
    childNodes.forEach(childNode= > node.appendChild(childNode));

    // the DOM node is returned as the mount node
    returnnode; }}Copy the code

The main difference from the mountHost() refactoring is that this.node and this.renderedChildren are now associated with internal DOM component instances. We’ll use it for non-destructive updates later.

Therefore, each internal instance (composite or host) now points to its child internal instance. To aid visualization, if the function

component renders the

[object CompositeComponent] {
  currentElement: <App />,
  publicInstance: null,
  renderedComponent: [object CompositeComponent] {
    currentElement: <Button />,
    publicInstance: [object Button],
    renderedComponent: [object DOMComponent] {
      currentElement: <div />,
      node: [object HTMLDivElement],
      renderedChildren: []
    }
  }
}
Copy the code

In the DOM, all you see is

. However, the internal instance tree contains both composite and host internal instances.

Compound internal instances need to store:

  • The current element
  • Public instance if the current element type is a class
  • A single rendered internal instance. It can beDOMComponentorCompositeComponent.

Internal computer instances need to be stored:

  • The current element
  • DOM node
  • Internal instances of all children, each of which can beDOMComponentorCompositeComponent.

If you’re struggling to imagine how to build an internal instance tree in a more complex application, React DevTools can give you an approximation because it highlights computer instances in gray, as well as composite instances in purple:

To accomplish this refactoring, we’ll introduce a function that installs the entire tree into the container node, like reactdom.render (). It returns a public instance, also like reactdom.render ():

function mountTree(element, containerNode) {
  // Create an internal instance of the top layer
  var rootComponent = instantiateComponent(element);

  // Mount the top-level component to the container
  var node = rootComponent.mount();
  containerNode.appendChild(node);

  // Returns the public instance he provides
  var publicInstance = rootComponent.getPublicInstance();
  return publicInstance;
}

var rootEl = document.getElementById('root');
mountTree(<App />, rootEl);
Copy the code

uninstall

Now that we have internal instances to hold their child nodes and DOM nodes, we can implement unload. For composite components, unload invokes lifecycle methods and recurses.

class CompositeComponent {

  // ...

  unmount() {var publicInstance = this.publicinstance;if (publicInstance) {
      if(publicInstance.componentWillUnmount) { publicInstance.componentWillUnmount(); } } // Unmount the single rendered component var renderedComponent = this.renderedComponent; renderedComponent.unmount(); }}Copy the code

For DOMComponent, unload tells each child node to unload:

class DOMComponent {

  // ...

  unmount() {
    // Unmount all children
    var renderedChildren = this.renderedChildren;
    renderedChildren.forEach(child= >child.unmount()); }}Copy the code

In fact, unloading the DOM component also removes the event listener and clears some of the cache, but we’ll skip over those details.

We can now add a named unmountTree (containerNode) new top function, it is similar to ReactDOM. UnmountComponentAtNode () :

function unmountTree(containerNode) {
  // Read the internal instance from the DOM node
  // (this doesn't work right now, we'll need to change the mountTree() method to store it)
  var node = containerNode.firstChild;
  var rootComponent = node._internalInstance;

  // Clear the container and unload the tree
  rootComponent.unmount();
  containerNode.innerHTML = ' ';
}
Copy the code

For this to work, we need to read the internal root instance from the DOM node. We will modify mountTree() to add the _internalInstance attribute to the DOM root node. We’ll also have mountTree() destroy any existing tree so that it can be called multiple times:

function mountTree(element, containerNode) {
  // Destroy existing trees
  if (containerNode.firstChild) {
    unmountTree(containerNode);
  }

  // Create an internal instance of the top layer
  var rootComponent = instantiateComponent(element);

  // Mount the top-level component to the container
  var node = rootComponent.mount();
  containerNode.appendChild(node);

  // Save a reference to the internal instance
  node._internalInstance = rootComponent;

  // Returns the public instance he provides
  var publicInstance = rootComponent.getPublicInstance();
  return publicInstance;
}
Copy the code

Now, repeat unmountTree() or mountTree() to remove the old tree and run the componentWillUnmount() lifecycle method on the component.

update

In the previous section, we implemented uninstallation. However, if each prop change causes the entire tree to be uninstalled and installed, React will not look very useful. The goal of the coordinator is to reuse existing instances as much as possible to preserve DOM and state:

var rootEl = document.getElementById('root');

mountTree(<App />, rootEl); // The existing DOM mountTree should be reused.<App />, rootEl);
Copy the code

We will extend our internal instance in another way. In addition to mount() and unmount(), both DOMComponent and CompositeComponent implement a new method called Receive (nextElement) :

class CompositeComponent {
  // ...

  receive(nextElement) {
    // ...}}class DOMComponent {
  // ...

  receive(nextElement) {
    // ...}}Copy the code

Its job is to do everything possible to keep the component (and any of its children) in sync with the description provided by nextElement.

This is what is often described as the “virtual DOM distinction,” although what really happens is that we recursively traverse the internal tree and make each internal instance receive updates.

Updating composite components

When a composite component receives a new element, we run the componentWillUpdate() lifecycle method.

We then re-render the component using the new props and get the next render element:

class CompositeComponent {

  // ...

  receive(nextElement) {
    var prevProps = this.currentElement.props;
    var publicInstance = this.publicInstance;
    var prevRenderedComponent = this.renderedComponent;
    var prevRenderedElement = prevRenderedComponent.currentElement;

    // Update the own element
    this.currentElement = nextElement;
    var type = nextElement.type;
    var nextProps = nextElement.props;

    // What is the output of the next render()
    var nextRenderedElement;
    if (isClass(type)) {
      / / class components
      // Call the lifecycle when necessary
      if (publicInstance.componentWillUpdate) {
        publicInstance.componentWillUpdate(nextProps);
      }
      / / update the props
      publicInstance.props = nextProps;
      // Re-render
      nextRenderedElement = publicInstance.render();
    } else if (typeof type === 'function') {
      // Functional components
      nextRenderedElement = type(nextProps);
    }

    // ...
Copy the code

Next, we can look at the type of the render element. If type has not changed since the last render, the following components can also be updated from the previous ones.

For example, if is returned the first time and the second time, we can tell the corresponding internal instance to receive() the next element:

	// ...

    // If the element type is not changed,
    // Reuse existing component instances
    if (prevRenderedElement.type === nextRenderedElement.type) {
      prevRenderedComponent.receive(nextRenderedElement);
      return;
    }

    // ...
Copy the code

However, if the next rendered element is of a different type than the previously rendered element, we cannot update the internal instance. cannot become .

Instead, we must unmount the existing internal instance and mount the new instance corresponding to the element type being rendered. For example, this happens when a component that previously rendered renders :

	// ...

	// If we reach this point, then we need to unmount the previously mounted components
	// Mount the new ones and swap their nodes

	// Find the old node, because we need to replace it
    var prevNode = prevRenderedComponent.getHostNode();

	// Unmount the old child and mount the new child
    prevRenderedComponent.unmount();
    var nextRenderedComponent = instantiateComponent(nextRenderedElement);
    var nextNode = nextRenderedComponent.mount();

    // Replace references to children
    this.renderedComponent = nextRenderedComponent;

	// The new node replaces the old one
	// Remember: the following code is platform-specific, ideally outside of the CompositeComponentprevNode.parentNode.replaceChild(nextNode, prevNode); }}Copy the code

In summary, when a composite component receives a new element, it can delegate the update to the internal instance it renders, or uninstall it and install the new instance in its place.

Under another condition, the component will be reinstalled instead of receiving the element, that is, the element’s key has changed. We won’t discuss key handling in this document because it adds more complexity to an already complex tutorial.

Note that we need to add a method called getHostNode() to the internal instance protocol so that the platform-specific node can be found and replaced during the update. Its implementation is simple for both classes:

class CompositeComponent {
  // ...

  getHostNode() {
    // Request the render component to provide it
    // This will recursively compound components downward
    return this.renderedComponent.getHostNode(); }}class DOMComponent {
  // ...

  getHostNode() {
    return this.node; }}Copy the code

Replacement of computer components

Computer component implementations, such as DOMComponent, are updated in different ways. When they receive the element, they need to update the underlying platform-specific view. In the React DOM case, this means updating the DOM attribute:

class DOMComponent {
  // ...

  receive(nextElement) {
    var node = this.node;
    var prevElement = this.currentElement;
    var prevProps = prevElement.props;
    var nextProps = nextElement.props;    
    this.currentElement = nextElement;

    // Remove the old attributes
    Object.keys(prevProps).forEach(propName= > {
      if(propName ! = ='children'&&! nextProps.hasOwnProperty(propName)) { node.removeAttribute(propName); }});// Set the following properties
    Object.keys(nextProps).forEach(propName= > {
      if(propName ! = ='children') { node.setAttribute(propName, nextProps[propName]); }});// ...
Copy the code

Then, the computer components need to update their child components. Unlike composite components, they may contain multiple child components.

In this simplified example, we take an array of internal instances and iterate over it, updating or replacing the internal instance based on whether the received type matches the previous type. In addition to inserting and deleting, a real coordinator would use the element’s keys to track movement, but we’ll omit this logic.

We collect sub-DOM operations in a list to execute them in batches:

	// ...

    // React Elements array
    var prevChildren = prevProps.children || [];
    if (!Array.isArray(prevChildren)) {
      prevChildren = [prevChildren];
    }
    var nextChildren = nextProps.children || [];
    if (!Array.isArray(nextChildren)) {
      nextChildren = [nextChildren];
    }
    // This is an array of internal instances:
    var prevRenderedChildren = this.renderedChildren;
    var nextRenderedChildren = [];

	// As we iterate over the children, we will add operations to the array
    var operationQueue = [];

	// Note: The following part is very simple!
	// It exists only to illustrate the process, not the details.

    for (var i = 0; i < nextChildren.length; i++) {
      // Try to get an existing internal instance of this child
      var prevChild = prevRenderedChildren[i];

      // If there is no internal instance under the index, append the child to the end.
      // Create a new internal instance, mount it and use its nodes
      if(! prevChild) {var nextChild = instantiateComponent(nextChildren[i]);
        var node = nextChild.mount();

        // Record the nodes we need to append
        operationQueue.push({type: 'ADD', node});
        nextRenderedChildren.push(nextChild);
        continue;
      }

      // We can update only instances where the element type matches.
       Can be updated to 
      // But can not be updated to 
      (i.e. element type mismatch)
      var canUpdate = prevChildren[i].type === nextChildren[i].type;

      // If the existing instance cannot be updated, we must remove it
      // And mount a new one to replace it
      if(! canUpdate) {var prevNode = prevChild.getHostNode();
        prevChild.unmount();

        var nextChild = instantiateComponent(nextChildren[i]);
        var nextNode = nextChild.mount();

        // Record the nodes we need to swap
        operationQueue.push({type: 'REPLACE', prevNode, nextNode});
        nextRenderedChildren.push(nextChild);
        continue;
      }

      If we can update an existing internal instance
      // Just let him receive the next element and handle his own updates
      prevChild.receive(nextChildren[i]);
      nextRenderedChildren.push(prevChild);
    }

	// Finally unload the child of the element that does not exist
    for (var j = nextChildren.length; j < prevChildren.length; j++) {
      var prevChild = prevRenderedChildren[j];
      var node = prevChild.getHostNode();
      prevChild.unmount();

      // Record the nodes we need to remove
      operationQueue.push({type: 'REMOVE', node});
    }

	// Point the rendered child list to the updated version
    this.renderedChildren = nextRenderedChildren;

    // ...
Copy the code

As a final step, we perform DOM operations. Again, the real coordination code is more complex because it also handles movement:

	// ...

    // Process the operation queue.
    while (operationQueue.length > 0) {
      var operation = operationQueue.shift();
      switch (operation.type) {
      case 'ADD':
        this.node.appendChild(operation.node);
        break;
      case 'REPLACE':
        this.node.replaceChild(operation.nextNode, operation.prevNode);
        break;
      case 'REMOVE':
        this.node.removeChild(operation.node);
        break; }}}}Copy the code

This is updating the DOMComponent

The top update

Now that both CompositeComponent and DOMComponent implement the receive(nextElement) method, we can change the top-level mountTree() function to use it when the element type is the same as last time:

function mountTree(element, containerNode) {
  // Check for existing trees
  if (containerNode.firstChild) {
    var prevNode = containerNode.firstChild;
    var prevRootComponent = prevNode._internalInstance;
    var prevElement = prevRootComponent.currentElement;

    // If we can, reuse the existing root component
    if (prevElement.type === element.type) {
      prevRootComponent.receive(element);
      return;
    }

    // Unmount existing trees in other cases
    unmountTree(containerNode);
  }

  // ...

}
Copy the code

Now call mountTree() twice with the same type without damaging updates:

var rootEl = document.getElementById('root');

mountTree(<App />, rootEl);
// Reuses the existing DOM:
mountTree(<App />, rootEl);
Copy the code

These are the basics of the inner workings of React.

What are we missing

This document is simplified compared to the real code base. We have not addressed several important aspects:

  • Components can be renderednullAnd the coordinator can handle the “empty” in the array and render the output.
  • The coordinator also reads from the elementkeyAnd use it to determine which internal instance corresponds to which element in the array. Much of the complexity in the actual React implementation is related to this.
  • In addition to composite and internal computer instance classes, there are classes for “text” and “empty” components. They represent text nodes and pass renderingnullObtain “empty slots”.
  • Renderer useinjectionPasses computer internal classes to the coordinator. For example,React DOMTell the coordinator to useReactDOMComponentImplemented as an internal instance of the computer.
  • The logic for updating the subitem list is extracted to nameReactMultiChildthemixinIt is composed ofReact DOMandReact NativeIn the computer internal instance class implementation.
  • The coordinator also implements pairs in composite componentssetState()Support. Multiple updates within an event handler are batched as a single update.
  • The coordinator is also responsible for attaching and detaching references to composite components and computer nodes.
  • Lifecycle methods that are invoked after the DOM is ready (e.gcomponentDidMount()andcomponentDidUpdate()) will be collected in a “callback queue” and executed in a single batch.
  • React puts information about the current update into an internal object called “Transaction.” Transaction is useful for tracking the queue of life-cycle methods to be processed, for warning about the nesting of the current DOM, and for anything else that is “global” for a particular update. The transaction also ensures React “cleans up everything” after updates. For example,React DOMThe provided transaction class restores the input selection after any updates.

Enter the code

  • ReactMountIt’s in this tutorialmountTree()andunmountTree()Code like that. He is responsible for installing and unloading components from the top layer.ReactNativeMountIt’s a React Native simulation.
  • ReactDOMComponentEquivalent to that in this tutorialDOMComponent. It implements the React DOM renderer’s computer component classes.ReactNativeBaseComponentReact Native simulation.
  • ReactCompositeComponentIs equivalent to that in this tutorialCompositeComponent. It handles user-defined components and maintains state.
  • instantiateReactComponentUse to select the inner instance class to construct for the element. It is equivalent to the one in this tutorialinstantiateComponent().
  • ReactReconcilerIs in themountComponent().receiveComponent().unmountComponent()Methods. It calls the underlying implementation on the internal instance, but also includes some code shared by all internal instance implementations.
  • The ReactChildReconciler implementation handles the queue of insert, delete, and move operations of the child levels independently of the renderer.
  • For legacy reasons,mount().receive()andunmount()It’s actually called in the React code basemountComponent().receiveComponent()andunmountComponent(), but they receive elements.
  • Attributes on internal instances begin with an underscore, for example_currentElement. They are considered read-only public fields throughout the code base.

Future development direction

The Stack Reconciler has inherent limitations, such as synchronization and the inability to interrupt work or break it into chunks. The new Fiber Reconciler is under way (PEN: Of course, as everyone knows, it has been completed by now), and they have completely different structures. In the future, we intend to replace the stack coordinator with this, but for now it is far from functional verification.

The next step

Read the next section for our guidelines for React development.

译 文 : Implementation Notes

React implementation records