Chapter 1 of 4

Why State Exists

The difference between a value that survives a render and one that does not.

A plain variable inside a component is recreated from scratch on every render. That makes it useless for anything the user changes.

The click updates the variable, but nothing re-renders and the next render resets it to 0.
function BrokenCounter() {
  let count = 0;

  return (
    <button onClick={() => { count = count + 1; }}>
      Clicked {count} times
    </button>
  );
}

Two things are missing. React does not know the value changed, so it never re-renders; and even if it did, count would be initialised back to 0.

State fixes both

useState gives a component a value React remembers between renders, plus a function that both updates the value and tells React to re-render.

import { useState } from "react";

function Counter() {
  const [count, setCount] = useState(0);

  return (
    <button onClick={() => setCount(count + 1)}>
      Clicked {count} times
    </button>
  );
}

Reading the signature

  • useState(0) takes the initial value, used only on the first render.
  • It returns an array of exactly two things, which you destructure.
  • The first item is the current value for this render.
  • The second is the setter, which schedules an update and a re-render.

The rules of hooks

React matches each useState call to its stored value by call order, so the calls must happen in the same order on every render.

  • Call hooks at the top level of a component, never inside a condition, loop or nested function.
  • Call hooks only from React components or from other custom hooks.
// Wrong: the hook only runs sometimes, so the order changes
if (isLoggedIn) {
  const [name, setName] = useState("");
}

// Right: always call it, use the value conditionally
const [name, setName] = useState("");