Course
Streaming
Next.js Mastery: From Fundamentals to Full-Stack
Unlock the power of Next.js with this comprehensive course! Starting with the basics, you’ll learn essential skills such as routing, data fetching, and styling. Progress through practical projects, including building your own React Notes app, to gain hands-on experience. Dive into the source code to understand the inner workings and core principles of Next.js. Perfect for developers with a basic knowledge of React and Node.js, this course ensures you’ll be ready to create high-performance full-stack applications efficiently. Join us and master Next.js, backed by industry experts and a supportive learning community.
Introduction
The technology behind Suspense is called Streaming. Streaming splits the HTML of a page into multiple chunks, which are then sent from the server to the client progressively.
This approach allows parts of the page to be displayed faster without waiting for all data to load before rendering the UI. Components that are sent earlier can start hydrating sooner, allowing users to interact with already hydrated components while other parts are still loading, effectively improving the user experience.
Streaming prevents long data fetches from blocking the entire page load. It can also reduce Time to First Byte (TTFB) and First Contentful Paint (FCP), helping to shorten Time to Interactive (TTI), especially on slower devices.
Traditional SSR:
With Streaming:
Usage
There are two ways to implement Streaming in Next.js:
- At the page level using
loading.jsx
- For specific components using
<Suspense>
<Suspense>
was introduced in the previous section, and loading.jsx
was covered in "Routing: App Router." Here's a tip for using loading.jsx
when multiple pages share the same loading effect: you can use route groups.Here's the directory structure:
scssCopy codeapp├─ (dashboard)│ ├─ about│ │ └─ page.js│ ├─ settings│ │ └─ page.js│ ├─ team│ │ └─ page.js│ ├─ layout.js│ └─ loading.js
The
app/(dashboard)/layout.js
code:javascriptCopy codeimport Link from 'next/link';
export default function DashboardLayout({ children }) { return ( <section> <nav className="flex items-center justify-center gap-10 text-blue-600 mb-6"> <Link href="/about">About</Link> <Link href="/settings">Settings</Link> <Link href="/team">Team</Link> </nav> {children} </section> );}
The
app/(dashboard)/loading.js
code:javascriptCopy codeexport default function DashboardLoading() { return ( <div className="h-60 flex-1 rounded-xl bg-indigo-500 text-white flex items-center justify-center"> Loading </div> );}
The
app/(dashboard)/about/page.js
code:javascriptCopy codeconst sleep = ms => new Promise(r => setTimeout(r, ms));
export default async function About() { await sleep(2000); return ( <div className="h-60 flex-1 rounded-xl bg-teal-400 text-white flex items-center justify-center"> Hello, About! </div> );}
The remaining components are similar to the About component. The final effect is as follows:
Drawbacks
While Suspense and Streaming are great for transforming traditional SSR into progressive rendering and hydration, they don't solve all problems. For example, the JavaScript code that users download remains the same size. Do users really need to download that much JavaScript? Also, all components must be hydrated on the client, but not all components need to be interactive.
To address these issues, the current ultimate solution is React Server Components (RSC), introduced in the previous article:
This doesn't mean RSC can replace Suspense. In fact, they can be used together for better performance. We'll explore this combination in our practical project sections.
References
- Next.js Documentation
- Vercel Blog: How Streaming Works
- Builder.io Blog: Why React Server Components