Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
React (Virtual) DOM Terminology

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 object through React.createElement.

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

To render a new tree into the DOM, you create ReactElements and pass them to React.render a long 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.

React.render(root, document.body);

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);
React.render(root, document.body);

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>;
React.render(root, document.body);

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' });
React.render(root, document.body);

React already have 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 React.render, React will call the constructor for you and create a ReactComponent, which returned.

var component = React.render(element, document.body);

If you keep calling React.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 = React.render(<MyComponent />, document.body);
var componentB = React.render(<MyComponent />, document.body);
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 is created or if the existing one is 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.

Formal Type Definitions

Entry Point

React.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>,
  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
};

jhegedus42 commented Nov 8, 2016

Can someone please comment on this related SOF question : http://stackoverflow.com/questions/40480745/what-does-react-render-return-component-instance-or-component-class

In React.render = (ReactElement, HTMLElement | SVGElement) => ReactComponent; it's not immediately clear to me if ReactComponent here refers to a class or an instance ?

My guess is that it is an instance.

If so it might be useful to rename ReactComponent to ReactComponentInstance in that case because if ReactComponentClass is returned by React.createClass then what is returned be React.render ?

Also, it would be good to include what is the type of React.createElement and React.createClass functions, into the formal type definitions.

Or wait, is ReactClass a ReactComponentClass ? Is ReactClass returned by React.createClass ?

ustun commented Dec 17, 2016

When writing type annotating, it is customary to write the type (class) of the return type.

foo : ReactComponent means it is a ReactComponent instance.

Initial letters of classes are usually capitalized, the instances are lowercase. So, the return type of React.render is ReactComponent means that it returns a reactComponent, an instance.

ustun commented Dec 17, 2016

Note the usage of "the" and "a". The ReactComponent is class, a ReactComponent is an instance. So, when we say "a", it means one of the many possible outcomes of the class, "the".

I started a new react tutorial website and found this page useful when doing my research. Thank you!

omg, it is a very nice note !!!

type ReactNodeList = ReactNode | ReactEmpty;
should be
type ReactNodeList = Array<ReactNode | ReactEmpty> ; ???

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment