In React's terminology, there are five core types that are important to distinguish:
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.
A ReactNode can be either:
ReactElementstring(akaReactText)number(akaReactText)- Array of
ReactNodes (akaReactFragment)
These are used as properties of other ReactElements to represent children. Effectively they create a tree of ReactElements.
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 thisOther 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; // trueThis 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.
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
};
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.