UI updating, in its essential, is data change. React offers a straightforward and intuitive approach to front-end program with all the moving parts converged in the form of states. Code review is also made easier to me as I like to start with data structures for a rough expectation of the functionalities and processing logic. From time to time, I was curious about how React works internally, hence this article.
It never hurts to have a deeper understanding down the stack, as it gives me more freedom when I need a new feature, more confidence when I want to contribute and more comfort when I upgrade.
This article will start walking through one of the critical paths of React by rendering a simple component, i.e., a <h1>. Other topics (e.g., Composite components rendering, state driven UI updating and components life cycle) will be discussed in the following articles in a similar, actionable manner.
Files used in this article:
isomorphic/React.js: entry point of ReactElement.createElement()
isomorphic/classic/element/ReactElement.js: workhorse of ReactElement.createElement()
renderers/dom/ReactDOM.js: entry point of ReactDOM.render()
renderers/dom/client/ReactMount.js: workhorse of ReactDom.render()
renderers/shared/stack/reconciler/instantiateReactComponent.js: create different types of ReactComponents based on element type
renderers/shared/stack/reconciler/ReactCompositeComponent.js: ReactComponents wrapper of root element
Tags used in the call stack:- function call= alias~ indirect function call
As the locations of source code files can not be obviously derived from import statement in the flat module tree, I will use @ to help locating them in the code snippet listings.
Last words, this series is based on React 15.6.2.
From JSX to React.createElement()
I was not consciously aware of using
React.createElement(), as the existence of it is masked by JSX from a developer’s point of view.
In compiling time, components defined in JSX is translated by Babel to React.createElement() called with appropriate parameters. For instance, the default App.js shipped with create-react-app:
1 | import React, { Component } from 'react'; |
is compiled to:
1 | import React, { Component } from 'react'; |
which is the real code executed by a browser. The code above shows a definition of a composite component App, in which JSX, a syntax of interweaving HTML tag in JavaScript code (e.g., <div className=”App”></div>), is translated to React.createElement() calls.
On the application level, this component will be rendered:
1 | ReactDOM.render( |
normally by a JS entry module named “index.js”.
This nested components tree is a bit too complicated to be an ideal start point, so we forget it now and instead look at something easier - that renders a simple HTML element.
1 | ... |
the babeled version of the above code is:
1 | ... |
React.createElement() - create a ReactElement
The first step does not do much really. It simply constructs an ReactElement instance populated with whatever passed down to the call stack. The outcome data structure is:

The call stack is:
1 | React.createElement |
React.createElement(type, config, children) is merely an alias of ReactElement.createElement();
1 | ... |
ReactElement.createElement(type, config, children) 1) copies the elements in config to props, 2) copies the children to props.children and 3) copies the type.defaultProps to props;
1 | ... |
Then ReactElement(type ,... ,props) copies the type and props as they are to ReactElement and returns the instance.
1 | ... |
The fields populated in the newly constructed ReactElement will be used directly by ReactMount.instantiateReactComponent(), which will be explained in detail very soon. Note that the next step will also create a ReactElement object with ReactElement.createElement(), so I will call the ReactElement object of this phase ReactElement[1].
ReactDom.render() - and render it
_renderSubtreeIntoContainer() - attach TopLevelWrapper to the ReactElement[1]
The purpose of the next step is to wrap the ReactElement[1] with another ReactElement (we call the instance a [2]) and set the ReactElement.type with TopLevelWrapper. The name TopLevelWrapper explains what it does - wrap the top level element of the component tree passed through render():

An important definition here is that of TopLevelWrapper, I type three stars here *** for you to CTL-f, as you might need to come back to this definition later.
1 | ... |
Please note that the entity assigned to ReactElement.type is a type (TopLevelWrapper) which will be instantiated in the following rendering steps. (Then ReactElement[1] will be extracted from this.props.child through render().)
The call stack to construct the designated object is as following:
1 | ReactDOM.render |
For initial rendering, ReactMount._renderSubtreeIntoContainer() is simpler than it seems to be, in fact, most branches (for UI updating) in this function are skipped. The only line that is effective before the logic processes to next step is
1 | ... |
Now that it should be easy to see how the target object of this step is constructed with React.createElement, the function we just examined in the last section.
instantiateReactComponent() - create a ReactCompositeComponent using ReactElement[2]
The purpose of this is step is to create a primitive ReactCompositeComponent for the top level component:

The call stack of this step is:
1 | ReactDOM.render |
instantiateReactComponent is the only long function that is worth discussing here. In our context, it checks the ReactElement[2].type (i.e., TopLevelWrapper) and creates a ReactCompositeComponent accordingly.
1 | function instantiateReactComponent(node, shouldHaveDebugID) { |
It is worth noting that new ReactCompositeComponentWrapper() is a direct call of ReactCompositeComponent constructor:
1 | ... |
Then the real constructor get called:
1 | construct: function(element) { |
We name the object created in this step ReactCompositeComponent[T] (T for top).
After the ReactCompositeComponent object is constructed, the next step is to call batchedMountComponentIntoNode, initialize ReactCompositeComponent[T] and mount it, which will be discussed in detail in the next article.