React Suspense: Building Better User Experiences Through Modern Loading Patterns


React Suspense represents a paradigm shift in how we handle asynchronous operations in React applications. What began as a solution for code-splitting has evolved into a comprehensive feature that transforms how we think about loading states, data fetching, and user experience. This revolution in React development offers powerful tools for creating more responsive and maintainable applications.

Understanding the Fundamentals

The journey to understand Suspense begins with its basic principles. At React Summit 2020, Maurice de Beijer provided a foundational overview that has become increasingly relevant as Suspense has matured. His talk "Getting Started with Suspense and Concurrent Rendering" demonstrated how Suspense eliminates the traditional "loading state triangle" - the pattern of managing loading, error, and success states manually. Through practical examples, he showed how Suspense transforms this complex pattern into a more declarative approach:

import { Suspense } from 'react';
import { ProductDetails } from './ProductDetails';

function ProductPage() {
  return (
    <Suspense fallback={<LoadingSpinner />}>
      <ProductDetails id="123" />
    </Suspense>
  );
}

The mechanics behind this seemingly simple API are fascinating. At React Summit 2024, Charlotte Isambert delivered an enlightening deep dive in her talk "Inside React's Magic". She revealed how Suspense integrates with React's fiber architecture, explaining the sophisticated promise-based mechanism that enables components to pause rendering while waiting for data. Her presentation illuminated how Suspense coordinates with React's internal reconciler to manage these paused states efficiently, a crucial insight for developers looking to optimize their applications.

The Evolution of Data Fetching

The true power of Suspense becomes apparent in data fetching scenarios. Robert Balicki's groundbreaking presentation at React Summit US 2023, "Suspense for Data Fetching: How to Fetch During Render", introduced a paradigm shift that challenges traditional useEffect patterns. He demonstrated how fetching during render, while counterintuitive, provides better user experiences and simpler code:

// Modern resource pattern introduced by Balicki
const productResource = createResource(async (id) => {
  const response = await fetch(`/api/products/${id}`);
  return response.json();
});

function ProductDetails({ id }) {
  const product = productResource.read(id);
  // No loading state management needed!
  return <div>{product.name}</div>;
}

Building on these foundations, Tejas Kumar's presentation "Handling Data at Scale" at React Summit 2022 took the concept further. He demonstrated how these patterns scale to enterprise applications, showing real-world examples of managing multiple data dependencies while maintaining performance. Kumar's insights were particularly valuable for teams dealing with complex data requirements, as he showed how Suspense can elegantly handle scenarios involving multiple API calls and data transformations.

Error Handling and Boundary Management

The integration of error handling with Suspense presents unique challenges and opportunities. Maurice de Beijer's follow-up session at React Advanced 2021, "Concurrent Rendering Adventures", provided crucial insights into combining error boundaries with Suspense:

class ErrorBoundary extends React.Component {
  state = { hasError: false };

  static getDerivedStateFromError(error) {
    return { hasError: true };
  }

  render() {
    if (this.state.hasError) {
      return <ErrorFallback />;
    }
    return this.props.children;
  }
}

function ProductPage() {
  return (
    <ErrorBoundary>
      <Suspense fallback={<LoadingSpinner />}>
        <ProductDetails id="123" />
      </Suspense>
    </ErrorBoundary>
  );
}

De Beijer's examples demonstrated how careful placement of error boundaries can create resilient applications that gracefully handle both loading and error states.

Performance and Transitions

The performance implications of Suspense extend beyond simple loading states. Ivan Akulov's insightful presentation at React Summit 2024, "The Invisible Hand of React Performance", revealed how Suspense works with React's concurrent features to optimize rendering. His talk uncovered how useTransition can create smoother user experiences by prioritizing different types of updates:

function ProductList() {
  const [isPending, startTransition] = useTransition();
  const [selectedId, setSelectedId] = useState(null);

  function selectProduct(id) {
    startTransition(() => {
      setSelectedId(id);
    });
  }

  return (
    <div className={isPending ? 'loading' : ''}>
      {/* Render product list with smooth transitions */}
    </div>
  );
}

Server Components and Streaming

The landscape of server-side rendering has been transformed by Suspense's capabilities. Lenz Weber-Tronic's comprehensive investigation at React Advanced 2023, "The Rocky Journey of Data Fetching Libraries", revealed the challenges and solutions in implementing streaming SSR. His talk demonstrated how modern frameworks leverage Suspense to enable component-by-component streaming:

// Server Component example demonstrated by Weber-Tronic
async function ProductPage({ id }) {
  const product = await fetchProduct(id);
  return (
    <Suspense fallback={<Skeleton />}>
      <ProductDetails product={product} />
      <Suspense fallback={<ReviewsSkeleton />}>
        <ProductReviews productId={id} />
      </Suspense>
    </Suspense>
  );
}

Weber-Tronic's insights were particularly valuable in showing how nested Suspense boundaries enable progressive loading patterns that significantly improve perceived performance. His real-world examples demonstrated how to avoid common pitfalls in SSR implementations while maintaining optimal user experience.

GraphQL Integration and Data Management

The integration of Suspense with GraphQL opens up powerful new possibilities. At React Summit US 2023, Jerel Miller and Alessia Bellisario delivered an enlightening presentation titled "How to Use Suspense and GraphQL with Apollo". Their talk showcased Apollo Client's advanced Suspense features and demonstrated patterns for managing complex data requirements:

function ProductWithReviews({ id }) {
  // Using Apollo's Suspense-enabled hooks as demonstrated
  const { data } = useSuspenseQuery(PRODUCT_QUERY, {
    variables: { id },
    // Implementing caching strategies discussed in the talk
    fetchPolicy: 'cache-and-network'
  });

  return (
    <div>
      <ProductInfo product={data.product} />
      <Reviews reviews={data.product.reviews} />
    </div>
  );
}

The speakers shared invaluable insights about managing cache interactions and handling real-time updates while maintaining consistent loading states across the application.

Edge Computing and Performance Optimization

At React Advanced 2021, Sunil Pai's groundbreaking talk "Living on the Edge" revealed how Suspense can be leveraged in edge computing scenarios. Pai demonstrated how combining Suspense with edge computing platforms enables new patterns for performance optimization:

// Edge-optimized component pattern shown by Pai
function EdgeOptimizedProduct({ id }) {
  return (
    <Suspense fallback={<StreamingFallback />}>
      <EdgeData region="closest">
        <ProductDetails id={id} />
      </EdgeData>
    </Suspense>
  );
}

His presentation highlighted how these patterns can reduce time-to-first-byte while maintaining smooth user experiences, even in globally distributed applications.

Building Custom Suspense Implementations

Understanding how to create custom Suspense-like functionality becomes crucial as applications grow more sophisticated. Julian Burr's detailed exploration at React Summit US 2024, "Let's Build Suspense", provided deep insights into Suspense's internal workings. Burr's talk included practical examples of building custom resource handlers:

// Custom resource implementation based on Burr's patterns
function createResource(asyncFn) {
  let status = 'pending';
  let result;
  let suspender = asyncFn().then(
    r => {
      status = 'success';
      result = r;
    },
    e => {
      status = 'error';
      result = e;
    }
  );

  return {
    read() {
      if (status === 'pending') throw suspender;
      if (status === 'error') throw result;
      return result;
    }
  };
}

The Future of React Development

The evolution of frameworks supporting Suspense continues to accelerate. Ben Holmes's insightful presentation at React Advanced 2023, "Opt-in Design – The New Era of React Frameworks", highlighted how modern frameworks are adopting progressive enhancement patterns that leverage Suspense's capabilities. His examples demonstrated how frameworks can provide better developer experiences while maintaining optimal performance.

Taking a broader view, Ryan Carniato's illuminating talk at JSNation 2023, "SolidJS: Why All the Suspense?", offered valuable perspectives on how different frameworks approach similar challenges. His comparative analysis helped developers understand the broader context of async handling in modern web development.

Practical Implementation Guidelines

The practical application of Suspense requires careful consideration of user experience. Nikhil Sharma's comprehensive guide presented at React Summit Remote Edition 2021, "Road to a Better UX with Suspense", provided crucial insights into implementing Suspense in production applications. His examples demonstrated how to avoid common pitfalls while creating smooth, professional user experiences.

Conclusion

As React continues to evolve, Suspense remains at the forefront of modern application development. Through the insights shared in these conference talks, we can see how Suspense has transformed from a simple code-splitting solution into a comprehensive system for managing asynchronous operations. Whether you're building a small application or scaling to millions of users, understanding and properly implementing Suspense is crucial for creating optimal user experiences.

The patterns and practices demonstrated by these expert speakers show that while Suspense is powerful, it requires thoughtful implementation. By carefully considering boundary placement, concurrent features, and data fetching patterns, developers can create more responsive, maintainable, and user-friendly applications that deliver exceptional experiences to their users.

FAQ

React Suspense is a feature that helps manage loading states and asynchronous operations in React applications. It's important because it provides a declarative way to handle loading states, simplifies code complexity, and improves user experience by allowing developers to specify how the UI should behave while content is loading.

Suspense works with React Server Components by managing loading states across the server-client boundary. It allows for efficient streaming of content from the server and helps coordinate the rendering of components as they become available, improving the overall performance of server-rendered React applications.

Yes, Suspense can be used with GraphQL and Apollo Client. Apollo Client provides specific Suspense features that integrate with React's Suspense functionality, allowing for better management of loading states and data fetching in GraphQL applications. This includes support for features like the @defer directive for optimized data loading.

Suspense works closely with Concurrent Rendering in React to enable more fluid transitions and better user experiences. Concurrent Rendering allows React to work on multiple versions of the UI simultaneously, while Suspense helps manage the loading states and transitions between these different UI states.

Suspense improves data fetching by providing a more structured approach to handling loading states and async operations. It eliminates the need for manual loading state management, reduces race conditions, and allows for better coordination of multiple data fetching operations through Suspense boundaries.

Learn more about the topic from these talks

Road to a Better UX with Suspense and Concurrent UI
React Summit Remote Edition 2021React Summit Remote Edition 2021
9 min
Road to a Better UX with Suspense and Concurrent UI
This talk explores how React Suspense and Concurrent mode can enhance the user experience by controlling loading areas, prefetching data, and reducing loading time. It demonstrates how UseTransition can remove unnecessary loaders by skipping the loading state if data arrives within a specified time. The speaker advises using these experimental features in personal projects rather than enterprise applications. The talk concludes with an invitation to join the journey at Postman and thanks to the organizers, sponsors, speakers, and audience for making the conference a success.
Getting Started with Suspense and Concurrent Rendering in React
React Summit 2020React Summit 2020
125 min
Getting Started with Suspense and Concurrent Rendering in React
Featured Workshop
Maurice de Beijer
Maurice de Beijer
React keeps on evolving and making hard things easier for the average developer.
One case, where React was not particularly hard but very repetitive, is working with AJAX request. There is always the trinity of loading, success and possible error states that had to be handled each time. But no more as the `<Suspense />` component makes life much easier.
Another case is performance of larger and complex applications. Usually React is fast enough but with a large application rendering components can conflict with user interactions. Concurrent rendering will, mostly automatically, take care of this.
You will learn all about using <Suspense />, showing loading indicators and handling errors. You will see how easy it is to get started with concurrent rendering. You will make suspense even more capable combining it with concurrent rendering, the `useTransition()` hook and the <SuspenseList /> component.
Concurrent Rendering Adventures in React 18
React Advanced 2021React Advanced 2021
132 min
Concurrent Rendering Adventures in React 18
Top Content
Featured WorkshopFree
Maurice de Beijer
Maurice de Beijer
With the release of React 18 we finally get the long awaited concurrent rendering. But how is that going to affect your application? What are the benefits of concurrent rendering in React? What do you need to do to switch to concurrent rendering when you upgrade to React 18? And what if you don’t want or can’t use concurrent rendering yet?

There are some behavior changes you need to be aware of! In this workshop we will cover all of those subjects and more.

Join me with your laptop in this interactive workshop. You will see how easy it is to switch to concurrent rendering in your React application. You will learn all about concurrent rendering, SuspenseList, the startTransition API and more.
Handling Data at Scale for React Developers
React Summit 2022React Summit 2022
23 min
Handling Data at Scale for React Developers
This Talk discusses handling data at scale for React developers, including scaling databases and the need for search. It explores different ways to fetch data in React, such as using useEffect, fetch, and setState. The Talk also introduces Suspense for data fetching and how it improves user experience. It covers controlling React Suspense, handling search, and using render-as-you-fetch. The Talk concludes with a discussion on the RFC status and fetching in event handlers.
SolidJS: Why All the Suspense?
JSNation 2023JSNation 2023
28 min
SolidJS: Why All the Suspense?
Top Content
Suspense is a mechanism for orchestrating asynchronous state changes in JavaScript frameworks. It ensures async consistency in UIs and helps avoid trust erosion and inconsistencies. Suspense boundaries are used to hoist data fetching and create consistency zones based on the user interface. They can handle loading states of multiple resources and control state loading in applications. Suspense can be used for transitions, providing a smoother user experience and allowing prioritization of important content.
How to Use Suspense and GraphQL with Apollo to Build Great User Experiences
React Advanced 2023React Advanced 2023
29 min
How to Use Suspense and GraphQL with Apollo to Build Great User Experiences
Top Content
Watch video: How to Use Suspense and GraphQL with Apollo to Build Great User Experiences
Jerel Miller
Alessia Bellisario
2 authors
This Talk discusses using suspense and GraphQL with Apollo client to build great end user experiences. It explains the core concepts of React suspense and how to fetch data in suspense with Apollo client's new suspense hooks. The Talk also covers optimizing the loading experience by adding suspense boundaries, using the defer directive in GraphQL, and integrating suspense hooks with React 18 transitions. Future plans include new APIs like suspenseful use fragment and lazy use background query in Apollo client 3.9. Testing strategies for suspense in components and customizing loading states are also mentioned.
Suspense for Data Fetching: How to Fetch During Render
React Summit US 2023React Summit US 2023
5 min
Suspense for Data Fetching: How to Fetch During Render
Watch video: Suspense for Data Fetching: How to Fetch During Render
This talk discusses the best practices for fetching data during the initial render of a component in React. It emphasizes the importance of fetching in advance and avoiding fetching twice. The talk also highlights the need for an external cache to store information about API calls and the use of a cleanup function to avoid memory leaks. Additionally, the speaker mentions their library, react-disposable-state, which can be used for making side effects during render.
React Server Components Unleashed: A Deep Dive into Next-Gen Web Development
React Day Berlin 2023React Day Berlin 2023
149 min
React Server Components Unleashed: A Deep Dive into Next-Gen Web Development
Workshop
Maurice de Beijer
Maurice de Beijer
Get ready to supercharge your web development skills with React Server Components! In this immersive, 3-hour workshop, we'll unlock the full potential of this revolutionary technology and explore how it's transforming the way developers build lightning-fast, efficient web applications.
Join us as we delve into the exciting world of React Server Components, which seamlessly blend server-side rendering with client-side interactivity for unparalleled performance and user experience. You'll gain hands-on experience through practical exercises, real-world examples, and expert guidance on how to harness the power of Server Components in your own projects.
Throughout the workshop, we'll cover essential topics, including:- Understanding the differences between Server and Client Components- Implementing Server Components to optimize data fetching and reduce JavaScript bundle size- Integrating Server and Client Components for a seamless user experience- Strategies for effectively passing data between components and managing state- Tips and best practices for maximizing the performance benefits of React Server Components
The Suspense Quest - Inside React's Magic
React Summit 2024React Summit 2024
30 min
The Suspense Quest - Inside React's Magic
This Talk explores the suspense component in React and its benefits in handling fetched data. It delves into the rendering process of React components and how suspense anticipates requests. The offscreen fiber is introduced as a hidden component that ensures state continuity. The Talk also discusses the usage of suspense for handling concurrent queries and throwing promises, as well as the integration of Redux and the upcoming changes in React 19. Overall, the Talk provides insights into the workings of suspense and its potential applications in software development.
Let's Build Suspense 🥁
React Advanced 2024React Advanced 2024
20 min
Let's Build Suspense 🥁
Hi, my name is Julian, and I'm extremely excited to talk about suspense. Suspense allows you to render fallback UI while waiting for asynchronous tasks to resolve, making it the unsung hero of React components. In today's talk, I will explain why suspense is crucial for React server components. Before diving into server components, let's understand the history of web rendering and the problems it posed. We then introduced server-side rendering (SSR) and static-side generation (SSG) to address these issues. However, SSR had problems like large bundle sizes, slow hydration, and sluggish initial server response time. React server components solve these problems by allowing us to differentiate between static and dynamic components. But to address the third problem, we need suspense. Today, we'll build a simplified version of suspense on the server to demonstrate its conceptual working and how it improves the rendering process from classical SSR to streaming and out-of-order streaming. Let's dive into the code by building a movie app called Notflix. We have different sections like the title, cast members, and similar movies. The components fetch their own data asynchronously, making them server components. In the classical way of server-side rendering, we loop through the children, execute them as server components, and render the HTML response. To improve the user experience, we introduce streaming, which allows us to start the response on the server, keep the connection open, and add to the response document as data becomes available. By using the write method provided by Express, we can write to the response stream instead of collecting all the HTML. Dealing with promises in sequence ensures that components are rendered in the correct order. Although the server-side rendering has improved, there is still no loading state or proper handling of suspended children. To address this, we introduce suspense on the server and build a suspense component with a fallback UI and children. We keep track of suspended children using a simple object with unique identifiers. In the renderer, we check the suspended object and loop through the entries to handle each suspended child. To replace the loading state with the content once it's available, we need to execute asynchronous functions to collect and concatenate the content, delete the entry from the suspended object, and use JavaScript to handle the swapping of elements in the browser. To replace the fallback renderer with the content, we need to wrap the fallback in a diff and add an identifier using a data attribute. We can use the CSS trick of 'display: contents' to prevent the diff from affecting the layout. Next, we wrap the available content in a template tag to add it to the document without rendering. Finally, we use custom elements and a connected callback to swap the loading boundary with the content based on the identifier. This allows us to replace multiple fallback renderers. By wrapping each section in its own boundary, the user experience is significantly improved as each section can load independently. This approach also emphasizes the importance of using the platform's existing features and functionality, such as browser caching, to enhance performance. Thank you for watching and enjoy the rest of the conference!