React

React as a UI runtime

Dan Abramov posted this great overview of React.

Some programs output numbers. Other programs output poems. Different languages and their runtimes are often optimized for a particular set of use cases, and React is no exception to that.

React programs usually output a tree that may change over time. Let's call this the host tree, because it's part of the host environment, like DOM or iOS. It usually has it's own imperative API (appendChild() in DOM, for example).

React can be more performant by assuming that the host tree is stable (not changing too much over time) and regular (can be broken down in components an patterns). In the case of most UIs, these reasonable assumptions are correct.

A host instance is a node in the host tree. Host instances have properties and can have other host instances as children. As mentioned above, there usually exists an API to manipulate these host instances.

A renderer teaches React to talk to a specific host environment and manage its host instances. React renderers can work in mutating or persistent mode. Mutating mode is what you'd expect (host instances are completely mutable) and persistent mode is for host environments that don’t provide methods like appendChild() but instead clone the parent tree and always replace the top-level child.

In the host environment, a host instance (like a DOM node) is the smallest building block. In React, the smallest building block is a React element. React element is a plain JavaScript object that can describe a host instance:

javascript
// JSX is a syntax sugar for these objects.
// <button className="blue" />
{
type: 'button',
props: { className: 'blue' }
}

A React element is lightweight and has no host instance tied to it. Again, it is merely a description of what you want to see on the screen. They are immutable. If you want to render something different later, you will describe it with a new React element tree created from scratch. They are like frames in a movie.

Each React renderer has an entry point. It’s the API that lets us tell React to render a particular React element tree inside a container host instance. For example, in React DOM, ReactDOM.render is the entry point:

jsx
ReactDOM.render(
// { type: 'button', props: { className: 'blue' } }
<button className="blue" />,
document.getElementById('container')
);

React’s job is to make the host tree match the provided React element tree. The process of figuring out what to do to the host instance tree in response to new information is sometimes called reconciliation.

When ReactDOM.render is called is called twice with the same container, React needs to decide when to update the existing host instance to match a the React element, and when to create a new one.

An example:

jsx
// let domNode = document.createElement('button');
// domNode.className = 'blue';
// domContainer.appendChild(domNode);
ReactDOM.render(
<button className="blue" />,
document.getElementById('container')
);
// Can reuse host instance? Yes! (button → button)
// domNode.className = 'red';
ReactDOM.render(
<button className="red" />,
document.getElementById('container')
);
// Can reuse host instance? No! (button → p)
// domContainer.removeChild(domNode);
// domNode = document.createElement('p');
// domNode.textContent = 'Hello';
// domContainer.appendChild(domNode);
ReactDOM.render(<p>Hello</p>, document.getElementById('container'));
// Can reuse host instance? Yes! (p → p)
// domNode.textContent = 'Goodbye';
ReactDOM.render(<p>Goodbye</p>, document.getElementById('container'));

This raises a question of identity. The React element may be different every time, but when does it refer to the same host instance conceptually? React is quite smart and figures things out most of the time but with dynamic lists, it needs a little help.

This is why React nags you to specify a special property called key every time you include an array of elements in your output. A key tells React that it should consider an item to be conceptually the same even if it has different positions inside its parent element between renders.

Gatsby