Explain React 18’s concurrent features.
Concurrent rendering lets React pause/resume/abandon renders. Key features: automatic batching across async boundaries, `startTransition` / `useTransition` for non-urgent updates, `useDeferredValue` for lagging expensive derivations, Suspense for data + lazy components, streaming SSR with selective hydration. The model: urgent updates (input) preempt non-urgent (large list re-renders).
React 18 introduced concurrent rendering — the scheduler can pause/resume/abandon a render in progress, enabling responsiveness during heavy work.
Automatic batching
Pre-18: multiple state updates inside the same event handler were batched; updates inside setTimeout/Promise weren't.
// React 17: two renders. React 18: one render.
setTimeout(() => {
setA(1);
setB(2);
}, 0);startTransition / useTransition
Mark a state update as non-urgent. React can interrupt it for urgent input.
const [isPending, startTransition] = useTransition();
function onChange(e) {
setQuery(e.target.value); // urgent
startTransition(() => setResults(filter(...))); // can be interrupted
}Input stays snappy; the heavy filter is interruptible if the user types again.
useDeferredValue
For derived values:
const deferred = useDeferredValue(query);
const list = useMemo(() => filter(items, deferred), [deferred]);deferred lags during fast typing; React renders the old value first, the new one later.
Suspense improvements
- Server Components + streaming SSR flush HTML in chunks gated by Suspense.
- Selective hydration — React hydrates the components the user interacts with first.
Strict Mode
Double-mounts components in dev to surface missing cleanups (effects, subscriptions). Not a perf feature but related to the concurrent model.
Tradeoffs
- Effects can run twice in dev (Strict Mode).
useEffectdeps must be precise — the new model exposes stale-closure bugs more often.- Some libraries needed updates for compat.
Interview framing
"Concurrent rendering means React's scheduler can pause/abandon a render. The user-facing primitives are automatic batching (across async boundaries), startTransition / useTransition for non-urgent updates so input stays snappy, useDeferredValue for expensive derivations that should lag, and Suspense for data + lazy. Streaming SSR + selective hydration shorten time-to-interactive. The mental shift: not every state update has to render immediately."
Follow-up questions
- •Difference between startTransition and useDeferredValue.
- •What is selective hydration?
- •Why does Strict Mode double-mount in dev?
Common mistakes
- •Treating transitions as throttle.
- •Putting urgent UI updates inside startTransition.
- •Misunderstanding Strict Mode warnings as bugs.
Performance considerations
- •Transitions and deferred values keep INP low under load. Streaming SSR cuts perceived load time.
Edge cases
- •Synchronous flushSync escape hatch.
- •Concurrent rendering + non-concurrent libraries (older state libs).
- •Suspense fallback flickers without proper boundaries.
Real-world examples
- •Next.js App Router, Vercel docs, React 18 release blog.