Skip to content

Why React & the Model

Consider a counter. The imperative version tells the browser how to update, step by step:

// Imperative: you manage the DOM and keep it in sync by hand.
let count = 0;
const label = document.querySelector("#count");
document.querySelector("#inc").addEventListener("click", () => {
count += 1;
label.textContent = count; // you must remember to do this, everywhere
});

The bug surface is the “remember to update” part: every place that changes count must also update every piece of UI that depends on it. Miss one and the screen lies.

The declarative version describes what the UI is for a given state, and never touches the DOM:

// Declarative: describe the UI for the current state; React syncs the DOM.
function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}

There is no “update the label” step. You change count, and because the UI is described in terms of count, React re-renders and the screen is correct by construction. The class of “I forgot to update X” bugs disappears.

A React component is a function that takes props (inputs from its parent) and uses state (its own memory), and returns a description of UI.

// props flow in; state lives inside; the return describes the UI.
function Greeting({ name }) { // name is a prop
const [count, setCount] = useState(0); // count is state
return (
<div>
<p>Hello, {name}</p>
<button onClick={() => setCount(count + 1)}>Clicked {count} times</button>
</div>
);
}
flowchart LR
  props["props (from parent)"] --> comp["Component function"]
  state["state (own memory)"] --> comp
  comp --> ui["returns: UI description
(elements)"]
  ui --> react["React renders it"]
A component maps inputs to a UI description

Two rules fall out of “component is a function”:

  • Props are read-only. A component must never modify its own props — they belong to the parent. Data flows down.
  • Same inputs, same output. Given the same props and state, a component should render the same thing. That’s the purity requirement (a whole lesson later), and it’s what lets React re-run components freely.

Everything else in React is downstream of UI = f(state):

  • Hooks exist to give function components state and lifecycle without breaking the “just a function” model.
  • Reconciliation exists to turn “here’s the new UI description” into “here’s the minimal DOM change.”
  • Concurrent features (transitions, Suspense) exist because a pure f(state) can be computed, paused, and restarted safely.

You are not learning a pile of APIs; you are learning one equation and its consequences.

What is the main problem with imperative DOM updates that React solves?
What are the inputs to a React component?
What is true about props?