useState is the primary React Hook for storing data that changes over time—such as toggle switches, form input text, modal visibility, or shopping cart items. Calling useState(initialValue) returns a two-item array: the current state value and a setter function that updates the state and schedules a re-render.
Destructure [value, setValue] at the top of your component. Whenever the next state depends on the previous state (like incrementing a counter twice in one click), pass an updater function prev => prev + 1 instead of reading count + 1 directly.
import { useState } from 'react';
export function StepCounter() {
const [count, setCount] = useState(0);
function addTwo() {
setCount((prev) => prev + 1);
setCount((prev) => prev + 1);
}
return (
<div>
<p>Current count: {count}</p>
<button type="button" onClick={addTwo}>+2 Steps</button>
<button type="button" onClick={() => setCount(0)}>Reset</button>
</div>
);
}
React checks state changes using Object.is reference equality. Mutating an object or array in place leaves the memory reference unchanged, so React skips the re-render. Always create a new copy with spread syntax (...) or array methods like .map() and .filter().
const [profile, setProfile] = useState({ name: 'Nadia', plan: 'free' });
// Create a fresh object copy rather than mutating profile.plan
const upgradePlan = () => setProfile((prev) => ({ ...prev, plan: 'pro' }));
If computing initial state requires reading localStorage or parsing JSON, pass a function (useState(() => loadSavedDraft())) rather than calling loadSavedDraft() directly. React invokes the initializer function once on mount instead of re-running it on every render.
useState MistakessetState: Calling setCount(5); console.log(count); still prints the old value because state updates take effect on the next render, not synchronously mid-function.firstName + ' ' + lastName into a separate fullName state variable. Compute const fullName = ... directly during render.setState batch multiple updates together?In React 18 and 19, React batches all state setters inside event handlers, timeouts, and promises into a single re-render for smoother performance.
useState multiple times?Yes. Separate unrelated state variables into distinct useState calls, or group tightly coupled fields into one object or useReducer.
setState with the exact same value?React uses Object.is to detect no change and bails out without re-rendering children.
Sign in to track your learning journey, earn industry-recognized certificates, and join our elite developer community.
Quick Access With