Deferred Data and Suspense Streaming with Await0%
Deferred Data and Suspense Streaming with Await
Beginner12 min read•Updated: Jul 11, 2026
Deferred Data and Suspense Streaming with Await
1. The Slow Loader Bottleneck
While Data Loaders eliminate render waterfalls, they introduce a potential drawback:
A route will NOT render until ALL data inside its
loader function has finished resolving.Consider a course page:
- Fast Data (Critical): Course Title, Instructor, Description (Resolves in 80ms).
- Slow Data (Non-Critical): 500 Student Reviews & Discussion Threads (Resolves in 1800ms).
If you await both queries in the loader:
JavaScript
// ❌ BAD: Blocks the ENTIRE page transition for 1.8 seconds!
export async function loader({ params }) {
const course = await fetchCourse(params.id); // 80ms
const reviews = await fetchReviews(params.id); // 1800ms (Slow!)
return { course, reviews };
}
The user clicks a course link and sits waiting for 1.8 seconds while the screen does nothing!
2. The Solution: Deferred Data with defer
React Router provides defer() (or streaming promises in modern versions).
You await the critical fast data, but do NOT await the slow data. You pass the unresolved Promise directly into the response:
JavaScript
// src/pages/CourseDetail.jsx
import { defer } from 'react-router-dom';
export function courseDetailLoader({ params }) {
// 1. Await critical fast data (Page will transition in 80ms!)
const coursePromise = fetchCourse(params.id);
// 2. Do NOT await slow data!
const reviewsPromise = fetchReviews(params.id);
return defer({
course: await coursePromise, // Resolved synchronously
reviews: reviewsPromise // Unresolved Promise streamed to client!
});
}
3. Rendering Deferred Data with <Suspense> and <Await>
In your component:
- The critical data renders instantly.
- The slow data is wrapped inside React's
<Suspense>and React Router's<Await>component, showing a fallback skeleton while the promise resolves in the background!
JSX
import React, { Suspense } from 'react';
import { useLoaderData, Await } from 'react-router-dom';
export default function CourseDetail() {
const { course, reviews } = useLoaderData();
return (
<div className="course-page">
{/* 1. Fast data renders immediately! Zero delay! */}
<header>
<h1>{course.title}</h1>
<p>{course.description}</p>
</header>
{/* 2. Slow data streams in asynchronously without blocking page transition */}
<section className="reviews-section">
<h3>Student Discussion & Feedback</h3>
<Suspense fallback={<div className="skeleton-loader">Loading 500 reviews...</div>}>
<Await
resolve={reviews}
errorElement={<p className="text-red">Failed to load reviews.</p>}
>
{(resolvedReviews) => (
<ul className="reviews-list">
{resolvedReviews.map(r => (
<li key={r.id}>
<strong>{r.author}:</strong> {r.comment}
</li>
))}
</ul>
)}
</Await>
</Suspense>
</section>
</div>
);
}
4. Why This Architecture Delivers World-Class UX
- 1Perceived Performance: The page navigates in 80ms, delivering instant feedback to the user.
- 2Progressive Rendering: Fast content is readable immediately while secondary sections stream into place.
- 3Resilient Error Isolation: If the slow reviews API fails, the
<Await errorElement={...}>displays a localized error without breaking the main course view!
Interactive Quiz
Practice Quiz
Question 1
What problem does deferring data resolve in React Router?
Question 2
What two components are used together in JSX to render deferred promises?
Question 3
What should you pass to
resolve={...} on the <Await> component?Question 4
If the deferred promise rejects with an error, what component handles the error UI?
Question 5
In the loader, which data should be
awaited and which data should be deferred?Next Lesson
Protected Routes and Role-Based Access Guards
Continue learning with hands-on practice, examples, and exercises in the upcoming topic.
Related Lessons
| Previous Lesson | Next Lesson |
|---|---|
| React Router v6 Data Loaders and Actions | Protected Routes and Role-Based Access Guards |
Practice Quiz
Test your understanding of this lesson with 5 questions. Each question has one correct answer.