REACT

React Suspense: Syntax, Usage, and Examples

React Suspense is a powerful feature for handling asynchronous rendering in React applications. It lets you “pause” rendering while data or components are loading, and display a fallback UI instead—like a loading spinner or message.

How to Use Suspense in React

To use Suspense React components, wrap the part of your UI that might need to wait for something (like a lazy-loaded component) inside a <Suspense> boundary. You must also provide a fallback prop, which is rendered while the content is still loading.

Basic Syntax

import React, { Suspense, lazy } from 'react';

const LazyComponent = lazy(() => import('./MyComponent'));

function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <LazyComponent />
    </Suspense>
  );
}

In this example, React will load MyComponent asynchronously. While it’s loading, the UI shows “Loading…”. Once the component is ready, it renders in place.

  • Suspense: The boundary that waits
  • fallback: The UI shown while loading
  • lazy(): A function that enables dynamic importing of components

When to Use Suspense in React

The React suspense feature is useful anytime your UI depends on something asynchronous. While it originally supported only code-splitting, recent improvements extend its utility to data fetching, especially when combined with libraries like React Query.

Lazy-Loading Components

Suspense is ideal for deferring component loading until it’s needed. This improves initial load time and performance.

const Chart = lazy(() => import('./Chart'));

<Suspense fallback={<div>Loading chart...</div>}>
  <Chart />
</Suspense>

This is especially helpful in dashboards, analytics tools, or any app with heavy visual components.

Data Fetching with React Query Suspense

When using React Query, you can enable suspense mode so your data-fetching logic integrates directly with Suspense.

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      suspense: true,
    },
  },
});

Then in your component:

const { data } = useQuery(['user', userId], fetchUser);

<Suspense fallback={<p>Loading user...</p>}>
  <UserProfile user={data} />
</Suspense>

This allows you to avoid managing loading states manually. Instead, you delegate that to react query suspense, which works seamlessly with Suspense boundaries.

Coordinating Multiple Async Operations

If you have multiple components each fetching different data, wrapping them in a shared Suspense boundary lets you coordinate them cleanly.

<Suspense fallback={<div>Loading all widgets...</div>}>
  <WidgetA />
  <WidgetB />
  <WidgetC />
</Suspense>

This avoids each widget needing its own spinner and simplifies the visual feedback for users.

Examples of Suspense in React

Let’s look at a few hands-on cases where Suspense improves your codebase’s clarity and performance.

Example 1: Basic Lazy Component

import React, { Suspense, lazy } from 'react';

const Profile = lazy(() => import('./Profile'));

function Dashboard() {
  return (
    <Suspense fallback={<div>Loading profile...</div>}>
      <Profile />
    </Suspense>
  );
}

This defers the loading of the Profile component, improving the performance of the initial render.

Example 2: Nested Suspense

You can nest multiple Suspense boundaries to control loading feedback at a granular level.

<Suspense fallback={<div>Loading page...</div>}>
  <Header />
  <Suspense fallback={<div>Loading content...</div>}>
    <MainContent />
  </Suspense>
</Suspense>

This setup allows the header to show immediately while the main content loads separately, offering a smoother experience.

Example 3: react suspense example with Data Fetching

Here's how to combine Suspense with React Query in a more realistic scenario.

import { useQuery } from '@tanstack/react-query';

function UserProfile() {
  const { data } = useQuery(['user'], fetchUserData);
  return <div>Hello, {data.name}</div>;
}

function App() {
  return (
    <Suspense fallback={<div>Loading user data...</div>}>
      <UserProfile />
    </Suspense>
  );
}

This example highlights a clean data-fetching flow using suspense React integration with query hooks.

Learn More About Suspense in React

Concurrent Features and Future Potential

React Suspense plays a central role in React’s long-term vision of concurrent rendering. It works best with React 18’s concurrent features like startTransition, automatic batching, and the use hook.

For example:

import { startTransition } from 'react';

startTransition(() => {
  setSearchQuery(newQuery);
});

In the future, you'll be able to combine Suspense with streaming server-rendered content, allowing portions of a page to load progressively without blocking the entire UI.

Error Boundaries with Suspense

Suspense only handles “waiting.” For error handling, you still need error boundaries.

<ErrorBoundary fallback={<div>Something went wrong.</div>}>
  <Suspense fallback={<div>Loading...</div>}>
    <Profile />
  </Suspense>
</ErrorBoundary>

This ensures your app doesn’t crash if the component fails to load or fetch data.

Handling Fallback Content Gracefully

Instead of using plain <div>Loading...</div>, you can use richer fallback components to create better user experiences.

<Suspense fallback={<SkeletonCard />}>
  <UserCard />
</Suspense>

You can even animate transitions between fallback and real content, creating smooth fade-ins or skeleton loading states.

Suspense with useTransition and useDeferredValue

React 18 adds hooks like useTransition and useDeferredValue that help you better coordinate UI updates with Suspense.

const [isPending, startTransition] = useTransition();

startTransition(() => {
  setValue(newValue);
});

Combined with Suspense, this lets you prioritize quick interactions (like button clicks) and delay expensive renders (like charts).

Server Components and Suspense

React Server Components rely heavily on Suspense. They allow you to render parts of your application on the server and progressively stream them to the client.

<Suspense fallback={<div>Loading server component...</div>}>
  <ServerRenderedComponent />
</Suspense>

You’ll see more of this in frameworks like Next.js 13+ with app directory structure.

react suspense example in Next.js

If you're using Next.js, you can wrap server components or dynamic imports in Suspense just like in regular React:

import dynamic from 'next/dynamic';
import { Suspense } from 'react';

const DynamicChart = dynamic(() => import('../components/Chart'), {
  suspense: true,
});

export default function Dashboard() {
  return (
    <Suspense fallback={<div>Loading chart...</div>}>
      <DynamicChart />
    </Suspense>
  );
}

This is a great react suspense example that aligns with best practices in full-stack React apps.


React Suspense helps you write smoother, cleaner, and faster apps without wrestling with dozens of loading states. By treating loading like a first-class UI concept, it clears the path for better user experiences and more maintainable code. As support grows in tools like React Query and Next.js, Suspense is quickly becoming a must-have in every React developer’s toolkit.

Learn to Code in React for Free
Start learning now
button icon
To advance beyond this tutorial and learn React by doing, try the interactive experience of Mimo. Whether you're starting from scratch or brushing up your coding skills, Mimo helps you take your coding journey above and beyond.

Sign up or download Mimo from the App Store or Google Play to enhance your programming skills and prepare for a career in tech.

You can code, too.

© 2025 Mimo GmbH

Reach your coding goals faster