Give a Component Memory
useState
`useState` lets a component remember a value across renders. Call the setter, React re-renders with the new value.
What you'll learn
- Declare and read state with `useState`
- Update state and trigger a re-render
- Initialize state from a function for expensive setup
A component re-runs every time it renders. Local let variables
reset every time. useState gives a component a value that
survives across renders.
The Shape
import { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
Clicks: {count}
</button>
);
} useState(initial) returns a tuple:
count— the current valuesetCount— a function to change it
Naming convention: [thing, setThing].
How a Render Happens
- Component runs,
useState(0)returns[0, setCount] - React renders
<button>Clicks: 0</button> - User clicks → handler runs →
setCount(1) - React schedules a re-render of
Counter - Component runs again,
useStatereturns[1, setCount] - React updates the DOM to show “Clicks: 1”
The state belongs to React, not to your function. Your function just asks for it on each run.
State Types
State can hold any JS value — strings, numbers, booleans, arrays, objects.
const [name, setName] = useState("");
const [items, setItems] = useState([]);
const [user, setUser] = useState({ id: 0, name: "" });
const [open, setOpen] = useState(false); Setting the Same Value Does Nothing
If you call setCount(count) with the same value, React skips the
re-render (using Object.is to compare).
setCount(0); // count is already 0 → no re-render For objects and arrays, “same value” means same reference. A new object with the same shape is a different value:
// Re-renders, even though the contents look the same
setUser({ ...user }); Lazy Initialization
If computing the initial value is expensive, pass a function:
const [parsed, setParsed] = useState(() => JSON.parse(localStorage.getItem("data") || "{}")); The function runs only on the first render. Without the wrapper, the parse would run every render and be thrown away (wasted work).
Multiple State Variables
A component can have as many useState calls as you want. Keep
unrelated state in separate variables:
function ProfileForm() {
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [age, setAge] = useState(0);
return ( /* ... */ );
} When several values change together, a single object is sometimes cleaner — but flat variables are usually easier.
Up Next
State updates have a couple of subtleties. Time to look at them.
State Updates →