Course outline · 0% complete

0/28 lessons0%

Course overview →

UI as a function of data

lesson 1-2 · ~10 min · 2/28

UI as a function of data

The core React equation is:

UI = f(data)

Given the same data, the same UI comes out. Change the data, run f again, and get the new UI.

That property has a name from Advanced JavaScript, since a function whose output depends only on its input is pure. Purity is what makes the equation trustworthy, because a function that also read a global variable or the current time could return two different screens for the same data, and then no amount of getting the data right would guarantee a correct page.

We can feel the idea in plain JavaScript before touching React itself. In the next block, render is an ordinary function that takes a user object and returns a string of HTML. It never touches the DOM, and it only answers the question of what the screen should say for this data.

Running the equation by hand

render is called twice with different data and produces different UI, with no manual patching in between.

function render(user) {
  const banner = user.unread > 0
    ? "You have " + user.unread + " unread messages."
    : "You are all caught up.";
  return "<h1>Hello, " + user.name + "!</h1><p>" + banner + "</p>";
}

console.log(render({ name: "Amara", unread: 3 }));
console.log(render({ name: "Amara", unread: 0 }));

Output

<h1>Hello, Amara!</h1><p>You have 3 unread messages.</p>
<h1>Hello, Amara!</h1><p>You are all caught up.</p>

The two calls differ only in unread, and the whole output changes accordingly. Nothing in render knows that a previous call ever happened, which is why the second line has no trace of the number 3 in it.

The ternary picks the banner, which is conditional rendering in its rawest form. Unit 5 gives this its own lesson with JSX, and the shape is identical: an expression that evaluates to one description or another.

render is safe to call as many times as you like, and calling it twice with the same user gives the same string twice. That repeatability is the property React relies on when it re-runs your component function after every data change.

Note what the function does not do. It never asks what the screen currently says, and it never edits anything, so there is no way for it to leave the page half updated.

What React adds on top

Our render returns a string, and replacing a whole page with a new string would be slow and would lose things like cursor position in an input. React does better:

  • Your components return a lightweight description of the UI (element objects, not strings).
  • React compares the new description with the previous one. This comparison is often called diffing.
  • React then applies only the minimal real DOM changes, for example updating one text node instead of rebuilding the page.

So the mental model stays UI = f(data), and React makes it fast. Everything in the rest of this course, components, props, state, effects, hangs off this one equation.

Deriving a badge from data

renderBadge(product) returns "<span>SALE: NAME</span>" when product.onSale is true, and "<span>NAME</span>" otherwise.

function renderBadge(product) {
  if (product.onSale) {
    return "<span>SALE: " + product.name + "</span>";
  }
  return "<span>" + product.name + "</span>";
}

console.log(renderBadge({ name: "Keyboard", onSale: true }));
console.log(renderBadge({ name: "Mouse", onSale: false }));

Output

<span>SALE: Keyboard</span>
<span>Mouse</span>

The if returns early for the sale case, so the final return handles everything else. A template literal would read better than + concatenation here, as in ` <span>SALE: ${product.name}</span> `, and both are correct.

The important property is that onSale is never stored twice. There is no badgeText variable to keep in step with it, so a product cannot be on sale while its badge says otherwise, which is the whole failure mode from lesson 1-1.

This is the shape of every React component you are about to write. Data comes in as an argument, a description comes out as a return value, and nothing outside the function is touched along the way.

What React does when the data changes

React calls your function again, diffs the new description against the old one, and applies minimal DOM updates.

Three steps, and each one matters:

  1. Re-run. React calls your component function to get a fresh description of the UI for the new data.
  2. Diff. It compares that description with the previous one to find what actually differs.
  3. Patch. It edits only the DOM parts that changed, for example one text node rather than a whole subtree.

You never patch the DOM yourself, which is the entire trade this library offers. You give up direct control of the page and you get the guarantee that the page matches the data.

The diffing step is what makes the naive version of this idea practical. Replacing the whole page with a new string would also keep the screen in sync, and it would be slow and would destroy things a user cares about, such as scroll position, focus, and the text selected inside an input.

Worth noting the responsibility this leaves you. If the screen is wrong, either your data is wrong or your description of the UI is wrong, and those are the only two possibilities. That is a much smaller search space than the imperative version, where a correct data value and a correct description can still produce a stale screen.