SkillGridLearn computer science by doing

Rendering: how change becomes pixels

What a re-render really is, why the interface is a function of state, why list keys decide which row the browser reuses, and why measuring beats guessing.

14 min · 45 XP

A counter that works looks like magic for about a day. Then you add a list to the page, the rows start behaving strangely, and the magic turns into a question: what exactly happens between the click and the new pixels?

First, clear up the word. Reloading means the browser throws the page away and asks the server for everything again: a new document, new elements, and every bit of state you had is gone. A re-render is nothing like that. The page stays, the browser tab stays, and the component functions run again to produce a fresh description of the interface. Nobody talks to the server unless your code asks for data.

UserAppDOMreloadF5a completely new treere-renderclickonly the text that changedthe same tree, one detail updated

This is why people write the interface as a function of state. You do not describe the transition from the old screen to the new one. You describe what the screen should be for the current data, and let the framework work out the difference.

function Total({ items }) {
  const sum = items.reduce((acc, item) => acc + item.price, 0);
  return <p>{sum}</p>;
}

const view = <Total items={cart} />;Given the same basket, this function always returns the same total.

Now the classic bug. You draw a list from data, and every row gets a stable key that identifies the item, not its position.

function Rows({ items }) {
  return (
    <ul>
      {items.map((item, index) => (
        <li key={item.id}>{item.name}</li>
      ))}
    </ul>
  );
}

items.map((item) => <li>{item.name}</li>);The first version gives the framework a stable identity per row. The second gives it nothing.

The key is how the framework recognises that this row on screen is the same item as that one in the new data. Without keys it falls back to position: row one is row one, row two is row two. Add an item at the top of a list of text inputs and the values appear to jump one row down, because the browser kept the first input and merely changed the label above it. The data was never wrong. The rows were never matched to the right items.

If re-rendering a component is running a function again, why is it not terribly slow? Because it usually is not. One keystroke may run a handful of small functions that build a few hundred plain objects, and that is far cheaper than the browser drawing a frame. It is affordable in a way it simply was not twenty years ago, and modern applications are built on that fact.

Which is exactly why the honest advice about speed is boring: measure before you optimise. A page can re-render thousands of times a second and feel instant, while one badly sized image makes it feel broken. Guessing which part is slow is the least reliable tool available; the browser already ships profilers that will simply tell you.

Practice

  1. A counter updates its number instantly, the address in the browser bar does not change, and the rest of the page keeps its scroll position. What happened?

    Hints
    • Watch the address bar and the scroll position: a reload destroys and rebuilds those, a re-render does not.
    • A re-render goes through the same component functions again. It does not ask the server for the page again.
  2. A search box fetches results from an API once and then filters them locally on every keystroke. Put the steps in order.

    1. 1The component computes which results match the current text
    2. 2It returns the elements for the matching rows, each with a stable key
    3. 3The returned list is kept as state, so it survives the next runs
    4. 4The component asks the server for the list once
    5. 5The framework updates only the rows whose content changed
    Hints
    • Nothing can be computed before the data has been fetched, and nothing can be drawn before it has been computed.
    • The button is not the value. The click only asks for the change; the change itself happens in the next step.
  3. Match each situation with the honest explanation of what is going on.

    Hints
    • One column is about a value that changed, the other about what the browser does with it.
    • Ask which of these is true of the counter button and which is true of a page that reloads.