Edit on GitHub

React (Virtual) DOM Terminology

In React's terminology, there are five core types that are important to distinguish:

React Elements #

The primary type in React is the ReactElement. It has four properties: type, props, key and ref. It has no methods and nothing on the prototype.

You can create one of these objects through React.createElement.

var root = React.createElement('div');

To render a new tree into the DOM, you create ReactElements and pass them to ReactDOM.render along with a regular DOM Element (HTMLElement or SVGElement). ReactElements are not to be confused with DOM Elements. A ReactElement is a light, stateless, immutable, virtual representation of a DOM Element. It is a virtual DOM.

ReactDOM.render(root, document.getElementById('example'));

To add properties to a DOM element, pass a properties object as the second argument and children to the third argument.

var child = React.createElement('li', null, 'Text Content');
var root = React.createElement('ul', { className: 'my-list' }, child);
ReactDOM.render(root, document.getElementById('example'));

If you use React JSX, then these ReactElements are created for you. So this is equivalent:

var root = <ul className="my-list">
             <li>Text Content</li>
           </ul>;
ReactDOM.render(root, document.getElementById('example'));

Factories #

A ReactElement-factory is simply a function that generates a ReactElement with a particular type property. React has a built-in helper for you to create factories. It's effectively just:

function createFactory(type) {
  return React.createElement.bind(null, type);
}

It allows you to create a convenient short-hand instead of typing out React.createElement('div') all the time.

var div = React.createFactory('div');
var root = div({ className: 'my-div' });
ReactDOM.render(root, document.getElementById('example'));

React already has built-in factories for common HTML tags:

var root = React.DOM.ul({ className: 'my-list' },
             React.DOM.li(null, 'Text Content')
           );

If you are using JSX you have no need for factories. JSX already provides a convenient short-hand for creating ReactElements.

React Nodes #

A ReactNode can be either:

  • ReactElement
  • string (aka ReactText)
  • number (aka ReactText)
  • Array of ReactNodes (aka ReactFragment)

These are used as properties of other ReactElements to represent children. Effectively they create a tree of ReactElements.

React Components #

You can use React using only ReactElements but to really take advantage of React, you'll want to use ReactComponents to create encapsulations with embedded state.

A ReactComponent Class is simply just a JavaScript class (or "constructor function").

var MyComponent = React.createClass({
  render: function() {
    ...
  }
});

When this constructor is invoked it is expected to return an object with at least a render method on it. This object is referred to as a ReactComponent.

var component = new MyComponent(props); // never do this

Other than for testing, you would normally never call this constructor yourself. React calls it for you.

Instead, you pass the ReactComponent Class to createElement you get a ReactElement.

var element = React.createElement(MyComponent);

OR using JSX:

var element = <MyComponent />;

When this is passed to ReactDOM.render, React will call the constructor for you and create a ReactComponent, which is returned.

var component = ReactDOM.render(element, document.getElementById('example'));

If you keep calling ReactDOM.render with the same type of ReactElement and the same container DOM Element it always returns the same instance. This instance is stateful.

var componentA = ReactDOM.render(<MyComponent />, document.getElementById('example'));
var componentB = ReactDOM.render(<MyComponent />, document.getElementById('example'));
componentA === componentB; // true

This is why you shouldn't construct your own instance. Instead, ReactElement is a virtual ReactComponent before it gets constructed. An old and new ReactElement can be compared to see if a new ReactComponent instance should be created or if the existing one should be reused.

The render method of a ReactComponent is expected to return another ReactElement. This allows these components to be composed. Ultimately the render resolves into ReactElement with a string tag which instantiates a DOM Element instance and inserts it into the document.

React 0.14 introduced stateless functional components as an alternative way of defining components. Instead of being a class, it is a simple function that accepts props and is expected to return a ReactElement.

Formal Type Definitions #

Entry Point #

ReactDOM.render = (ReactElement, HTMLElement | SVGElement) => ReactComponent;

Nodes and Elements #

type ReactNode = ReactElement | ReactFragment | ReactText;

type ReactElement = ReactComponentElement | ReactDOMElement;

type ReactDOMElement = {
  type : string,
  props : {
    children : ReactNodeList,
    className : string,
    etc.
  },
  key : string | boolean | number | null,
  ref : string | null
};

type ReactComponentElement<TProps> = {
  type : ReactClass<TProps> | ReactFunctionalComponent<TProps>,
  props : TProps,
  key : string | boolean | number | null,
  ref : string | null
};

type ReactFragment = Array<ReactNode | ReactEmpty>;

type ReactNodeList = ReactNode | ReactEmpty;

type ReactText = string | number;

type ReactEmpty = null | undefined | boolean;

Classes and Components #

type ReactClass<TProps> = (TProps) => ReactComponent<TProps>;

type ReactComponent<TProps> = {
  props : TProps,
  render : () => ReactElement
};

type ReactFunctionalComponent<TProps> = (TProps) => ReactElement;