useState
useState stores a value that should survive between renders and update the UI when it changes.
const [value, setValue] = useState(initialValue);The first item is the current state for this render. The second item is a setter that schedules an update.
Basic Example
import { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
Count: {count}
</button>
);
}After setCount runs, React renders again with the new count.
State Is a Snapshot
State variables do not change inside the current render.
function handleClick() {
setCount(count + 1);
console.log(count); // previous render's value
}Think of count as a snapshot from the render that created this handler.
Functional Updates
When the next state depends on the previous state, use the functional form.
setCount((currentCount) => currentCount + 1);This matters when multiple updates happen close together.
setCount((count) => count + 1);
setCount((count) => count + 1);
setCount((count) => count + 1);This reliably adds 3.
Objects and Arrays
State should be treated as immutable. Create new objects and arrays instead of mutating existing ones.
setUser((user) => ({
...user,
name: "Ava",
}));setItems((items) => [...items, newItem]);Mutating state can prevent React from seeing that something changed and can make bugs very hard to trace.
Lazy Initial State
If the initial value is expensive to calculate, pass a function.
const [settings, setSettings] = useState(() => loadSettingsFromStorage());React calls this initializer only for the initial render.
Common Mistakes
Do not store values in state if they can be derived during render.
const fullName = `${firstName} ${lastName}`;This is better than keeping a separate fullName state that can fall out of sync.
Do not use state for values that do not affect rendering. Use useRef for mutable values like timer ids.
Which useState update is safest when the next value depends on the previous value?
Practice Challenge
Build a shopping cart component.
Requirements:
- add items without mutating the existing array
- remove items by id
- update quantity using a functional state update
- calculate the total during render instead of storing it separately
Recap
Use useState for render-affecting values. Treat state as immutable, prefer functional updates when state depends on previous state, and avoid storing values that can be calculated from existing props or state.