JS Guide
HomeQuestionsTopicsCompaniesResources
BookmarksSearch

Built for developers preparing for JavaScript, React & TypeScript interviews.

ResourcesQuestionsSupport
HomeQuestionsSearchProgress
HomeTopicsreactConcurrent React
PrevNext
react
advanced
12 min read

Concurrent React

code-splitting
concurrent
lazy
performance
suspense
useDeferredValue
useTransition

Concurrent rendering lets React interrupt and prioritize work — Suspense provides declarative loading states, useTransition marks updates as non-urgent, and useDeferredValue defers expensive re-renders.

Key Points

1Interruptible Rendering

React can pause mid-render to handle urgent updates (user input), then resume — the UI never shows incomplete state.

2Suspense

Declarative loading boundaries with fallback UI. Works with React.lazy for code splitting and data fetching frameworks for loading states.

3useTransition

Marks state updates as non-urgent — React renders in the background while keeping the current UI responsive. isPending shows transition status.

4useDeferredValue

Returns a value that lags behind during urgent updates — causes a lower-priority re-render that React can interrupt.

5Priority Model

User input (highest) > transitions > deferred values (lowest). Urgent work always takes precedence over background rendering.

What You'll Learn

  • Explain how concurrent rendering differs from synchronous rendering
  • Use Suspense for code splitting and data loading boundaries
  • Know when to use useTransition vs useDeferredValue

Deep Dive

Concurrent React (enabled by default since React 18) is a set of features that allow React to interrupt rendering work to handle more urgent updates. This keeps the UI responsive even during expensive state transitions.

Concurrent Rendering

In synchronous (pre-React 18) rendering, once React starts rendering a component tree, it can't stop until it's done. If rendering takes 300ms, the browser can't respond to user input during that time — the UI feels frozen.

Concurrent rendering makes rendering interruptible. React can pause mid-render to handle urgent work (user typing, clicking) and resume the interrupted render later. The user never sees an incomplete UI — React only commits the final result to the DOM.

Suspense

Suspense declares a loading boundary: <Suspense fallback={<Spinner />}><DataComponent /></Suspense>. When a child component is "suspended" (waiting for data, lazy-loaded code, etc.), React shows the fallback UI until the child is ready.

Suspense works with:

  • React.lazy() — code splitting. const Chart = lazy(() => import('./Chart')) loads the component bundle on demand.
  • Data fetching frameworks (Next.js, Relay, TanStack Query) that integrate with Suspense for loading states.
  • Server components with streaming SSR — the server streams HTML progressively, with Suspense boundaries marking where content is still loading.

Suspense boundaries can be nested: an outer boundary shows a page-level skeleton, inner boundaries show section-level loaders.

useTransition

const [isPending, startTransition] = useTransition() marks a state update as non-urgent. React keeps showing the current UI while rendering the new state in the background. isPending is true during the transition, letting you show a subtle indicator.

JavaScript
startTransition(() => {
  setSearchResults(filterLargeList(query));
});

The search input stays responsive (urgent update) while the results list updates in the background (non-urgent). Without transitions, the expensive filter blocks the input.

useDeferredValue

const deferredQuery = useDeferredValue(query) returns a deferred version of the value that lags behind the actual value during urgent updates. Similar to debouncing, but React-aware — it defers automatically based on rendering priority.

Use it when you can't wrap the state update in startTransition (e.g., the value comes from props). The deferred value causes a lower-priority re-render that React can interrupt.

startTransition

startTransition(callback) is the function form for use outside hooks (in event handlers, library code). Same behavior as useTransition but without isPending.

Priority Model

React's priority system: user input (typing, clicking) > transitions > deferred values. Urgent updates are processed immediately; non-urgent updates are interruptible and may be restarted if new urgent work arrives.

Key Interview Distinction

Concurrent rendering makes React interruptible — it can pause expensive renders to handle urgent input. Suspense is declarative loading states for code splitting and data fetching. useTransition marks updates as non-urgent to keep the UI responsive. useDeferredValue defers a value's update until urgent work completes. These features work together to eliminate UI jank in complex applications.

Fun Fact

Concurrent React was in development for over 4 years before shipping in React 18 (2022). The React team originally called it 'Async React' and demonstrated it at JSConf Iceland in 2018, but the complexity of making it backward-compatible while maintaining correctness took much longer than expected.

Learn These First

Hooks

intermediate

Performance Optimization

advanced

Continue Learning

Performance Optimization

advanced

React Internals

advanced

Practice What You Learned

What are React's concurrent features and how do Suspense and transitions work?
senior
concurrent
Concurrent React enables interruptible rendering, allowing React to pause low-priority work for urgent updates. Suspense handles async loading states declaratively. useTransition marks updates as non-urgent, and useDeferredValue defers expensive re-renders.
Previous
Components
Next
Context API
PrevNext