---
title: React as a UI Runtime
date: '2019-02-02'
spoiler: An in-depth description of the React programming model.
cta: 'react'
---
Most tutorials introduce React as a UI library. This makes sense because React *is* a UI library. That’s literally what the tagline says!

I’ve written about the challenges of creating [user interfaces](/the-elements-of-ui-engineering/) before. But this post talks about React in a different way — more as a [programming runtime](https://en.wikipedia.org/wiki/Runtime_system).
**This post won’t teach you anything about creating user interfaces.** But it might help you understand the React programming model in more depth.
---
**Note: If you’re _learning_ React, check out [the docs](https://reactjs.org/docs/getting-started.html#learn-react) instead.**
⚠️
**This is a deep dive — THIS IS NOT a beginner-friendly post.** In this post, I’m describing most of the React programming model from first principles. I don’t explain how to use it — just how it works.
It’s aimed at experienced programmers and folks working on other UI libraries who asked about some tradeoffs chosen in React. I hope you’ll find it useful!
**Many people successfully use React for years without thinking about most of these topics.** This is definitely a programmer-centric view of React rather than, say, a [designer-centric one](http://mrmrs.cc/writing/developing-ui/). But I don’t think it hurts to have resources for both.
With that disclaimer out of the way, let’s go!
---
## Host Tree
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**. It might be a [DOM tree](https://www.npmjs.com/package/react-dom), an [iOS hierarchy](https://developer.apple.com/library/archive/documentation/General/Conceptual/Devpedia-CocoaApp/View%20Hierarchy.html), a tree of [PDF primitives](https://react-pdf.org/), or even of [JSON objects](https://reactjs.org/docs/test-renderer.html). However, usually, we want to represent some UI with it. We’ll call it a “*host* tree” because it is a part of the *host environment* outside of React — like DOM or iOS. The host tree usually has [its](https://developer.mozilla.org/en-US/docs/Web/API/Node/appendChild) [own](https://developer.apple.com/documentation/uikit/uiview/1622616-addsubview) imperative API. React is a layer on top of it.
So what is React useful for? Very abstractly, it helps you write a program that predictably manipulates a complex host tree in response to external events like interactions, network responses, timers, and so on.
A specialized tool works better than a generic one when it can impose and benefit from particular constraints. React makes a bet on two principles:
* **Stability.** The host tree is relatively stable and most updates don’t radically change its overall structure. If an app rearranged all its interactive elements into a completely different combination every second, it would be difficult to use. Where did that button go? Why is my screen dancing?
* **Regularity.** The host tree can be broken down into UI patterns that look and behave consistently (such as buttons, lists, avatars) rather than random shapes.
**These principles happen to be true for most UIs.** However, React is ill-suited when there are no stable “patterns” in the output. For example, React may help you write a Twitter client but won’t be very useful for a [3D pipes screensaver](https://www.youtube.com/watch?v=Uzx9ArZ7MUU).
## Host Instances
The host tree consists of nodes. We’ll call them “host instances”.
In the DOM environment, host instances are regular DOM nodes — like the objects you get when you call `document.createElement('div')`. On iOS, host instances could be values uniquely identifying a native view from JavaScript.
Host instances have their own properties (e.g. `domNode.className` or `view.tintColor`). They may also contain other host instances as children.
(This has nothing to do with React — I’m describing the host environments.)
There is usually an API to manipulate host instances. For example, the DOM provides APIs like `appendChild`, `removeChild`, `setAttribute`, and so on. In React apps, you usually don’t call these APIs. That’s the job of React.
## Renderers
A *renderer* teaches React to talk to a specific host environment and manage its host instances. React DOM, React Native, and even [Ink](https://mobile.twitter.com/vadimdemedes/status/1089344289102942211) are React renderers. You can also [create your own React renderer](https://github.com/facebook/react/tree/master/packages/react-reconciler).
React renderers can work in one of two modes.
The vast majority of renderers are written to use the “mutating” mode. This mode is how the DOM works: we can create a node, set its properties, and later add or remove children from it. The host instances are completely mutable.
React can also work in a [“persistent”](https://en.wikipedia.org/wiki/Persistent_data_structure) mode. This 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. Immutability on the host tree level makes multi-threading easier. [React Fabric](https://facebook.github.io/react-native/blog/2018/06/14/state-of-react-native-2018) takes advantage of that.
As a React user, you never need to think about these modes. I only want to highlight that React isn’t just an adapter from one mode to another. Its usefulness is orthogonal to the target low-level view API paradigm.
## React Elements
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*.
A React element is a plain JavaScript object. It can *describe* a host instance.
```jsx
// JSX is a syntax sugar for these objects.
//
{
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.
Like host instances, React elements can form a tree:
```jsx
// JSX is a syntax sugar for these objects.
//
{
type: 'dialog',
props: {
children: [{
type: 'button',
props: { className: 'blue' }
}, {
type: 'button',
props: { className: 'red' }
}]
}
}
```
*(Note: I omitted [some properties](/why-do-react-elements-have-typeof-property/) that aren’t important to this explanation.)*
However, remember that **React elements don’t have their own persistent identity.** They’re meant to be re-created and thrown away all the time.
React elements are immutable. For example, you can’t change the children or a property of a React element. If you want to render something different later, you will *describe* it with a new React element tree created from scratch.
I like to think of React elements as being like frames in a movie. They capture what the UI should look like at a specific point in time. They don’t change.
## Entry Point
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, React DOM entry point is `ReactDOM.render`:
```jsx
ReactDOM.render(
// { type: 'button', props: { className: 'blue' } }
,
document.getElementById('container')
);
```
When we say `ReactDOM.render(reactElement, domContainer)`, we mean: **“Dear React, make the `domContainer` host tree match my `reactElement`.”**
React will look at the `reactElement.type` (in our example, `'button'`) and ask the React DOM renderer to create a host instance for it and set the properties:
```jsx {3,4}
// Somewhere in the ReactDOM renderer (simplified)
function createHostInstance(reactElement) {
let domNode = document.createElement(reactElement.type);
domNode.className = reactElement.props.className;
return domNode;
}
```
In our example, effectively React will do this:
```jsx {1,2}
let domNode = document.createElement('button');
domNode.className = 'blue';
domContainer.appendChild(domNode);
```
If the React element has child elements in `reactElement.props.children`, React will recursively create host instances for them too on the first render.
## Reconciliation
What happens if we call `ReactDOM.render()` twice with the same container?
```jsx {2,11}
ReactDOM.render(
,
document.getElementById('container')
);
// ... later ...
// Should this *replace* the button host instance
// or merely update a property on an existing one?
ReactDOM.render(
,
document.getElementById('container')
);
```
Again, 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](https://reactjs.org/docs/reconciliation.html).
There are two ways to go about it. A simplified version of React could blow away the existing tree and re-create it from scratch:
```jsx
let domContainer = document.getElementById('container');
// Clear the tree
domContainer.innerHTML = '';
// Create the new host instance tree
let domNode = document.createElement('button');
domNode.className = 'red';
domContainer.appendChild(domNode);
```
But in DOM, this is slow and loses important information like focus, selection, scroll state, and so on. Instead, we want React to do something like this:
```jsx
let domNode = domContainer.firstChild;
// Update existing host instance
domNode.className = 'red';
```
In other words, React needs to decide when to _update_ an existing host instance to match a new React element, and when to create a _new_ one.
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?
In our example, it’s simple. We used to render a `