One source of truth & a render function

Keep state, then render

Lesson 9 of 20 · 13 min · Module 3: State, storage and accessibility

As pages grow, keeping the page and your data in step by hand becomes the main source of bugs. A simple pattern fixes that: keep all data in one place, and redraw the page from it whenever it changes.

Start this lesson →

Free. No installation: you write and run the code in your browser, and it is checked automatically.

By the end, you’ll be able to…

  • Keep data in one place
  • Draw the page from data with a render function
  • Update state in listeners, then render

The idea

Store the data in an array of objects. Write one render() function that builds the whole list from that array, for example with replaceChildren(). Event listeners never touch the page directly: they update the array and call render(). The page can then never disagree with the data.

let count = 0;
function render() {
  document.querySelector('#count').textContent = count;
}
button.addEventListener('click', () => { count += 1; render(); });
render();

01Data is the source of truth

When the page itself holds the information, for example by reading which boxes are ticked, every feature has to inspect the DOM. Keeping an array makes counting, filtering and saving trivial.

02Redraw instead of patching

Re-creating a short list on every change is fast and removes a whole class of bugs. replaceChildren() swaps all children in one step.

list.replaceChildren(...items.map(makeItem)); // new children
list.replaceChildren();                       // empty list

03This is how frameworks work

React, Vue and Svelte are built on the same idea: state changes, and the view is derived from state. Learning the pattern by hand makes those tools much easier to understand later.

Your turn

Complete render(): rebuild #todo-list from todos, with one <li> per todo containing a <label> with a checkbox (checked when done, with data-id set to the todo’s id) and the text. Give done items the class done, and show 1 of 3 done in #summary. Add one change listener on the list that updates the todo’s done value in the array and calls render(), and make #clear remove all done todos from the array.

What the checks look for

  • The list is drawn from the data
  • The summary and the done class match the data
  • Ticking a box updates the summary
  • Unticking works too
  • Clear completed removes done items
  • The page stays in sync after several steps
Try it in the editor →

Take this with you

Change the data, then render: the page follows the state.

Go a little further

Add a filter with three buttons (All, Open, Done) stored in a variable that render() respects.

Learn JavaScript in the Browser for free

20 short lessons with real code and instant checks.

See the whole course →