Search⌘ K
AI Features

What Suspense Is and Why It Exists

Explore how React Suspense helps manage asynchronous data fetching by coordinating rendering and preventing partial UI updates. Understand the concept of Suspense boundaries as commit gates that improve user experience through stable, atomic feature reveals. Learn best practices for designing Suspense boundaries, preloading data to avoid waterfalls, and using transitions for smoother UI updates.

React apps often fetch data with a straightforward pattern: render the component, start a request usually in an effect like useEffect, store the result in state, and show a spinner while isLoading is true. In a small app, this feels natural because everything is fetched locally, logic sits next to the UI that uses it, and there are only a few loading states to think about.

The problems start when the UI becomes more complex and more connected. A single screen might need user info, permissions, a list of items, and details for the selected item, often coming from different endpoints. In a model where each component handles its own data loading, components render independently and trigger their own network requests during initialization. That’s how you get the classic experience where the header loads, then the sidebar appears, then the main content flashes in, then a nested section shows its own spinner, and the layout shifts multiple times as data arrives.

This is what people mean by “spinner hell,” but it’s not only about too many spinners. It’s about a lack of coordination. The app has no clear rule for when a full feature is “ready,” because readiness is determined by multiple components. Users see a page that feels unstable: parts flicker, placeholders come and go, and it’s hard to tell whether the app is still loading or just broken.

There’s also a deeper technical cost. When data isn’t ready, components still mount and render, just in a defensive mode. You end up writing lots of:

  • if (!data) return <Spinner />;

  • data?.field ?? "—"

  • separate “Loading” and “Real” versions of the same component

  • duplicated rules for errors, empty states, and partial data

Over time, this pattern propagates through the component tree and tightly couples data-fetch timing with rendering logic. A component ...