Design Converter
Education
Last updated on Feb 12, 2025
•6 mins read
Last updated on Feb 12, 2025
•6 mins read
Software Development Executive - II
I know who I am.
Modern single-page applications (SPAs) often require fast, responsive navigation. One challenge developers face is waiting for all data to load before rendering a route. This can lead to a blank screen or a sluggish user experience. React Router’s defer
function addresses this problem by allowing parts of your data to load asynchronously—even after the UI is rendered.
In this article, we’ll explore the defer
function, how deferred data loading works, and when and how to implement it in your React application.
Traditionally, React Router’s route loaders wait for all asynchronous data (via promises) to resolve before the component is rendered. For example, if you have a route that must fetch critical and non-critical data, your route won’t render until every promise resolves. This “waterfall” loading can delay the initial render, even if some data isn’t immediately necessary for the first paint.
“With traditional loaders, the entire route is blocked until every promise resolves. This can lead to a slower perceived performance if one or more requests are delayed.”
defer
Function?React Router’s defer
function changes the paradigm by allowing you to return promises directly from your loader. Instead of waiting for every piece of data to load, you can “defer” non-critical data so that the route’s component renders immediately with placeholders (using React’s Suspense). When the deferred promises resolve, the UI updates automatically.
For example, consider a loader that fetches product details (critical) and product reviews (non-critical). With defer
, you can immediately display the product details and render a “Loading…” message for the reviews.
When you use defer
in your loader, you effectively tell React Router to separate the data-fetching responsibilities:
await
to resolve the promise before returning. This ensures that essential UI elements are ready.1import { 2 defer, 3 useLoaderData, 4 Await, 5} from "react-router-dom"; 6import React from "react"; 7import { getProduct, getProductReviews } from "./api"; 8 9export async function loader({ params }) { 10 // Await critical data immediately: 11 const product = await getProduct(params.productId); 12 // Return non-critical data as a promise (deferred): 13 const reviewsPromise = getProductReviews(params.productId); 14 15 return defer({ product, reviews: reviewsPromise }); 16} 17 18export default function ProductPage() { 19 const { product, reviews } = useLoaderData(); 20 21 return ( 22 <main> 23 <h1>{product.name}</h1> 24 <p>{product.description}</p> 25 26 <React.Suspense fallback={<p>Loading reviews…</p>}> 27 <Await resolve={reviews}> 28 {(reviewsData) => ( 29 <ul> 30 {reviewsData.map((review) => ( 31 <li key={review.id}>{review.comment}</li> 32 ))} 33 </ul> 34 )} 35 </Await> 36 </React.Suspense> 37 </main> 38 ); 39}
Explanation:
<Await>
component (wrapped in <React.Suspense>
) suspends rendering of that part of the UI until the promise resolves. This ensures the page loads quickly while showing a fallback until the reviews are available.The diagram below provides a visual overview of the data loading flow when using defer
:
Diagram Explanation:
await
, ensuring it’s ready before rendering.<Suspense>
component wraps the non-critical part, showing a fallback UI while waiting.<Await>
component suspends rendering for non-critical data until its promise resolves.defer
?<Await>
to gracefully handle any rejected promises.defer
has been further streamlined. For example, some wrappers have been removed to simplify the API.“Deferred data loading is all about making the app feel faster by not blocking the entire UI on data that isn’t immediately necessary.”
<React.Suspense>
with meaningful fallback content. This fallback should inform the user that more data is loading.<Await>
components.defer
).The defer
function in React Router is a powerful tool for improving the performance and user experience of your applications. By returning unresolved promises from your loaders, you enable immediate rendering of critical UI elements while non-critical data loads in the background. This approach not only speeds up the initial page load but also provides a smoother, more responsive user experience.
By following best practices and staying updated with the latest documentation, you can seamlessly integrate deferred data loading into your React projects and build faster, more dynamic applications.
Happy coding!
Tired of manually designing screens, coding on weekends, and technical debt? Let DhiWise handle it for you!
You can build an e-commerce store, healthcare app, portfolio, blogging website, social media or admin panel right away. Use our library of 40+ pre-built free templates to create your first application using DhiWise.