EasyHooks📖 Theory Question

Explain useState — batching, functional updates, and lazy initialization.

💡

Hint

State updates are batched; use functional form for updates based on previous state; pass a function to useState for expensive initial computation

Full Answer

const [state, setState] = useState(initialValue);

Functional updates — use when next state depends on current state:

// ❌ Potentially stale closure
setCount(count + 1);
setCount(count + 1); // both read the same stale 'count'

// ✅ Always gets the latest value
setCount(c => c + 1);
setCount(c => c + 1); // correctly increments twice

Batching — React 18 batches all state updates (even in setTimeout, fetch callbacks) into a single re-render:

// React 18: both updates batched into ONE re-render
setTimeout(() => {
  setCount(c => c + 1);
  setName('Alice');
}, 0);

Lazy initialization — pass a function to avoid re-running expensive setup on every render:

// ❌ computeExpensive() runs every render (result discarded after mount)
const [state, setState] = useState(computeExpensive());

// ✅ Only runs on mount
const [state, setState] = useState(() => computeExpensive());
💡 State updates are asynchronous — you won't see the new value immediately after calling setState. React schedules a re-render; the new value appears in the next render's closure.

More Hooks Questions

EasyWhat are the Rules of Hooks and why do they exist?EasyHow does useEffect work? What are its dependency array behaviors?EasyWhat is the difference between useEffect and useLayoutEffect?EasyWhat is useRef and what are its two main use cases?

Practice this in a timed sprint →

5 free questions, no signup required

⚡ Start Sprint