Chapter 3 of 15
~12 minState & useState
State is data a component owns and can change over time, and `useState` is the hook that gives function components that ability. Whenever a piece of data changes and the UI needs to reflect it, that data belongs in state.
Why Props Alone Are Not Enough
Props let a component receive data, but they cannot change on their own from inside the component. State is different - it is local, mutable (through a setter, never directly), and updating it triggers React to re-render the component with the new value.
Declaring State with useState
`useState(initialValue)` returns a pair: the current value and a function to update it, conventionally destructured as `const [value, setValue] = useState(initialValue)`. Calling the setter schedules a re-render with the new value - it does not mutate the variable in place.
Try it yourself
A basic counterfunction Counter() { const [count, setCount] = useState(0); return ( <button onClick={() => setCount(count + 1)}> Clicked {count} times </button> ); } render(<Counter />);
State Updates Are Asynchronous and Batched
Calling the setter does not update `count` immediately in the current render - it schedules the update for the next render. React also batches multiple state updates that happen in the same event handler into a single re-render for performance, so logging the state variable right after calling its setter will still show the old value.
Functional Updates
When a new state value depends on the previous one, pass a function to the setter instead of a value: `setCount(prev => prev + 1)`. This guarantees you are always working from the most recent state, which matters especially when multiple updates happen close together (like several rapid clicks, or updates inside async code).
Try it yourself
Functional update avoids stale statefunction Counter() { const [count, setCount] = useState(0); const incrementTwice = () => { setCount(prev => prev + 1); setCount(prev => prev + 1); }; return ( <div> <p>Count: {count}</p> <button onClick={incrementTwice}>+2</button> </div> ); } render(<Counter />);
Count: 0
Each useState Call Is Independent
A component can call `useState` multiple times, each managing its own independent piece of state. There is no requirement to bundle everything into one big state object - in fact, splitting unrelated values into separate `useState` calls is usually simpler than merging them.
Try it yourself
Multiple independent state variablesfunction ProfileForm() { const [name, setName] = useState(''); const [isSubscribed, setIsSubscribed] = useState(false); return ( <div> <input value={name} onChange={e => setName(e.target.value)} placeholder="Name" /> <p>Hello, {name || 'stranger'}!</p> <label> <input type="checkbox" checked={isSubscribed} onChange={e => setIsSubscribed(e.target.checked)} /> Subscribe </label> <p>Subscribed: {isSubscribed ? 'yes' : 'no'}</p> </div> ); } render(<ProfileForm />);
Hello, stranger!
Subscribed: no
State With Objects and Arrays
When state holds an object or array, you must replace it with a new object/array rather than mutating it in place - React compares references to decide whether to re-render, so `state.push(x)` followed by `setState(state)` will not trigger an update. Use spread syntax instead: `setItems([...items, newItem])`.
Coding challenge
Build a Toggle component with a boolean state starting at false. Render a button that shows "ON" or "OFF" depending on the state, and flips it on click using a functional update.
function Toggle() { // write your code here return null; } render(<Toggle />);
Answer every question below to mark this chapter as complete.
Quiz Yourself
Score: 0/41. What does calling a useState setter function do?
2. Why use `setCount(prev => prev + 1)` instead of `setCount(count + 1)`?
3. How many times can a component call useState?
4. Why does `items.push(newItem); setItems(items);` fail to trigger a re-render?