React Suspense: A Beginner-to-Expert Guide

Amir Saeed
3 min readFeb 3, 2025

--

Introduction

React Suspense is a built-in feature in React that allows components to “wait” for something before rendering. It helps in handling code splitting, data fetching, and server-side rendering (SSR) while improving performance and user experience.

In this guide, we’ll cover everything from the basics to advanced use cases of React Suspense, including:

  • How Suspense works
  • Code Splitting with React.lazy()
  • Data Fetching with Suspense
  • Using Suspense in Server Components (Next.js App Router)
  • Streaming SSR with Suspense

1. Understanding React Suspense

What is Suspense?

React Suspense is a mechanism that allows React to pause rendering of a component until its dependencies (like data or lazy-loaded components) are ready. While waiting, React shows a fallback UI (like a loading spinner or skeleton screen).

Why Use Suspense?

  • 🚀 Improves Performance: Helps reduce JavaScript bundle size by lazy-loading components.
  • 🎯 Better User Experience: Prevents UI flickers and loads only the necessary content.
  • 🔥 Optimised Data Fetching: Works with React Server Components (RSC) to defer rendering until data is ready.

2. Basic Example: Lazy Loading with Suspense

One common use case of Suspense is code splitting, where you load components only when needed using React.lazy().

🔹 Example: Lazy Loading a Component

import React, { Suspense, lazy } from "react";
// Lazy load the component
const HeavyComponent = lazy(() => import("./HeavyComponent"));
export default function App() {
return (
<div>
<h1>Welcome to My App</h1>
<Suspense fallback={<p>Loading component...</p>}>
<HeavyComponent />
</Suspense>
</div>
);
}

🔍 How It Works:

  • lazy(() => import("./HeavyComponent")) dynamically loads the component when required.
  • <Suspense fallback={<p>Loading...</p>}> ensures a loading indicator is displayed while waiting.
  • This reduces the initial bundle size, speeding up the app’s loading time.

3. Using Suspense for Data Fetching

React Suspense can also be used for data fetching, especially with React Server Components (Next.js App Router).

🔹 Example: Fetching Data with Suspense (Next.js App Router)

import { Suspense } from "react";
import ProductList from "./ProductList";
export default function Page() {
return (
<div>
<h1>Products</h1>
<Suspense fallback={<p>Loading products...</p>}>
<ProductList />
</Suspense>
</div>
);
}

🔹 Server Component Fetching Example (ProductList.tsx)

async function getProducts() {
const res = await fetch("https://fakestoreapi.com/products");
return res.json();
}
export default async function ProductList() {
const products = await getProducts();
return (
<ul>
{products.map((product) => (
<li key={product.id}>{product.title}</li>
))}
</ul>
);
}

🔍 How It Works:

  • ProductList is an async Server Component that fetches data before rendering.
  • Suspense ensures that a loading state (Loading products...) is displayed until data is ready.
  • This removes the need for useEffect() or useState() for fetching data!

4. Streaming Server-Side Rendering (SSR) with Suspense

React 18 introduced Streaming SSR, allowing partial rendering of content as data loads.

🔹 Example: Streaming SSR (Next.js App Router)

import { Suspense } from "react";
import DynamicContent from "./DynamicContent";
export default function Page() {
return (
<div>
<h1>Streaming SSR Example</h1>
<Suspense fallback={<p>Loading content...</p>}>
<DynamicContent />
</Suspense>
</div>
);
}

🔹 Server Component with Delayed Data (DynamicContent.tsx)

async function fetchDelayedData() {
await new Promise((resolve) => setTimeout(resolve, 3000)); // Simulate delay
return "Here is the streamed content!";
}
export default async function DynamicContent() {
const data = await fetchDelayedData();
return <p>{data}</p>;
}

🔍 How It Works:

  • The page renders immediately, but DynamicContent loads after 3 seconds.
  • Suspense keeps the UI responsive while waiting for the streamed content.
  • Great for large pages where parts can be rendered incrementally.

5. Limitations of Suspense

❌ Doesn’t work with client-side fetching using useEffect() (yet).

❌ Requires special data-fetching libraries (e.g., React Server Components, Relay).

❌ Suspense for data fetching is still experimental outside of Next.js.

6. When to Use Suspense?

Code Splitting: Using React.lazy() for dynamically loading components.

Data Fetching in Server Components: Works best with Next.js App Router.

Streaming SSR: Incrementally rendering parts of a page for better performance.

Defer Rendering: Show UI placeholders while waiting for expensive computations.

Conclusion

React Suspense is a game-changer for performance and user experience. Whether you’re optimising your React app by lazy loading components, fetching data in Server Components, or leveraging Streaming SSR, Suspense makes your UI feel smoother and faster.

🚀 Key Takeaways:

  • Use React.lazy() with Suspense for code splitting.
  • Fetch data using Suspense in React Server Components (RSC).
  • Optimise Next.js performance with Streaming SSR.

Want to see Suspense in action? Try implementing lazy loading in your projects today! 🚀

📢 Have Questions? Drop them in the comments below! Happy coding! 🎉

--

--

Amir Saeed
Amir Saeed

Written by Amir Saeed

Senior Full Stack Developer | 15+ yrs experience | Expert in React, Angular, Node, TypeScript, JavaScript, Python,FastAPI, Terraform, AWS and modern tech.

No responses yet