Quiz
Warm-up from lesson 3-3: props are read-only, a component never changes its own props. So where does data that CHANGES over time, like a click counter, have to live?
Why components need state
Try to build a counter with a plain variable:
function Counter() { let count = 0; return ( <button onClick={() => { count = count + 1; }}> Clicked {count} times </button> ); }
Clicking does nothing visible. Two separate reasons:
- React does not know
countchanged, so it never re-renders. Nothing repaints the screen. - Even if it did re-render,
Counterwould run again from the top andlet count = 0would reset it.
We need a variable that survives re-renders and tells React when it changes. That is exactly what useState provides.
useState
import { useState } from "react"; function Counter() { const [count, setCount] = useState(0); return ( <button onClick={() => setCount(count + 1)}> Clicked {count} times </button> ); }
Read it piece by piece:
useState(0)declares a piece of state with initial value0. React stores it outside your function, so it survives re-renders.- It returns a pair, unpacked with array destructuring from Advanced JavaScript: the current value (
count) and a setter function (setCount). - Calling
setCount(1)does two things: stores the new value, and schedules a re-render of this component.
useState is a hook: a function whose name starts with use and that gives your component access to a React feature, here, stored state. React ships a small set of them, and useEffect in Unit 7 is the other one this course needs.
Why hooks must stay at the top level
There is one hard rule about hooks: call them at the top level of the component, never inside an if, a loop, or a nested function. The rule exists because of how React stores your state. Your component is a plain function, so useState cannot attach state to a variable name. Instead, React keeps a list of state slots per component and matches each useState call to a slot by the order of the calls: first call gets slot 1, second call gets slot 2, and so on, every render.
const [name, setName] = useState(""); // always slot 1 const [count, setCount] = useState(0); // always slot 2
Put a useState inside an if and some renders make two calls while others make one. The order shifts, slot 2's value lands in the wrong variable, and your name state suddenly holds a number. React detects this and throws an error rather than corrupting state, which is why the rule is enforced, not just recommended.
Quiz
What happens the moment setCount(5) is called?
Quiz
Spot the bug: ```jsx function Form({ showEmail }) { const [name, setName] = useState(""); if (showEmail) { const [email, setEmail] = useState(""); } ... } ```