React State and useState Hook
useState is the most-used React hook. Here's what interviews test — state updates, batching, and the patterns that trip people up.
useState basics
useState returns the current state and a setter function. Calling the setter triggers a re-render.
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0); // initial value: 0
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>+</button>
<button onClick={() => setCount(0)}>Reset</button>
</div>
);
}Functional updates
When the new state depends on the previous state, use a function to avoid stale closures.
// BUG: stale state — both clicks use the same 'count' value
<button onClick={() => {
setCount(count + 1);
setCount(count + 1); // still uses old count!
}}>+2</button>
// FIX: functional update — always uses latest state
<button onClick={() => {
setCount(prev => prev + 1);
setCount(prev => prev + 1); // correctly increments twice
}}>+2</button>Object and array state
When state is an object or array, always create a new reference — never mutate the existing one.
const [user, setUser] = useState({ name: "Alice", age: 25 });
// WRONG: mutates state directly
user.age = 26; // doesn't trigger re-render
setUser(user); // same reference, React may skip re-render
// CORRECT: spread to create new object
setUser({ ...user, age: 26 });
// Array state
const [items, setItems] = useState(["a", "b"]);
// Add item
setItems([...items, "c"]);
// Remove item
setItems(items.filter(item => item !== "b"));
// Update item
setItems(items.map(item => item === "a" ? "A" : item));Multiple state variables vs objects
Prefer multiple simple state variables over one big object when values change independently.
// Prefer this (values change independently):
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [loading, setLoading] = useState(false);
// Over this (single object — forces spreading on every update):
const [form, setForm] = useState({ name: '', email: '', loading: false });
setForm(prev => ({ ...prev, name: 'Alice' })); // verbose
// Exception: related values that change together
const [position, setPosition] = useState({ x: 0, y: 0 });
setPosition({ x: event.clientX, y: event.clientY });Exam tip
The most common useState interview question: "Why does my state update look stale?" — because setState calls are batched and the closure captures the value at render time. Always use functional updates (prev => ...) when new state depends on old state.
Think you're ready? Prove it.
Take the free React readiness test. Get a score, topic breakdown, and your exact weak areas.
Take the free React test →Free · No sign-up · Instant results