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.
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("");