Day 12 — Streaming & Suspense: Instant UI
🧭 Day 12 — Streaming & Suspense: Instant UI
Zero to Hero — Hands-on Next.js Tutorial
Problem: With traditional SSR, the user sees a blank white screen until everything is ready (DB calls, API fetches, etc.). If one slow query takes 3 seconds, the user waits 3 seconds for the entire page.
Solution: Streaming. Send the parts that are ready (Header, Sidebar) immediately. Send the slow parts (Charts, Feed) later, when they finish.
🟦 1. loading.tsx (Page Level)
The easiest way to stream is to add a loading.tsx file in your route folder.
Next.js will automatically wrap your page.tsx in a React Suspense boundary.
// src/app/dashboard/loading.tsx
export default function Loading() {
return <div className="text-xl font-bold">Loading Dashboard... ⏳</div>;
}
Now, when you visit /dashboard, you see “Loading Dashboard…” instantly.
When the async page.tsx finishes fetching, the loading UI is swapped with the real content.
🟩 2. Suspension (Component Level)
What if you have a fast part (User Profile) and a slow part (Sales Chart) on the same page? Don’t block the Profile waiting for the Chart!
Wrap the slow component in <Suspense>.
import { Suspense } from 'react';
import SalesChart from './SalesChart'; // This component fetches its own data
export default function Dashboard() {
return (
<main>
<h1>My Dashboard</h1>
{/* This loads instantly */}
<UserProfile />
{/* This shows "Loading Chart" until SalesChart is ready */}
<Suspense fallback={<p>Loading Chart...</p>}>
<SalesChart />
</Suspense>
</main>
);
}
🟧 3. Benefits of Streaming
- TTFB (Time To First Byte): Decreases massively. The server responds immediately.
- FCP (First Contentful Paint): The user sees the layout (Sidebar/Nav) instantly.
- TTI (Time To Interactive): React hydrates the visible parts while the hidden parts are still loading.
🧪 Challenge: Day 12
- Create a component
SlowComponentthat awaits anew Promise(resolve => setTimeout(resolve, 3000)). - Put it in your page. Notice the whole page hangs for 3s.
- Create a
loading.tsxnext to the page. - Notice how you see the loading state instantly now?
- Remove
loading.tsxand try wrapping just the component in<Suspense fallback={...}>.
See you tomorrow for Error Handling! 🚨