Tampilkan Konten Bertahap dengan Cara Streaming Data Server Component Next Js

Cara streaming data Server Component Next.js yang benar adalah membungkus komponen async yang lambat dengan Suspense. Shell halaman seperti header dan layout terkirim dulu, bagian daftar atau komentar menyusul setelah fetch selesai.

Kesalahan paling umum adalah membuat seluruh page.tsx jadi async karena satu fetch lambat. Satu promise lambat itu menahan seluruh halaman.

Kapan Streaming Dibutuhkan di Server Component

Halaman lambat punya dua penyebab berbeda. Fetch lambat terjadi saat API atau database merespons lama. Render berat terjadi saat komponen memproses data besar atau kalkulasi kompleks.

Streaming hanya membantu untuk kasus pertama, terutama konten yang boleh tampil belakangan.

  • Daftar produk, artikel terkait, atau rekomendasi yang fetch-nya lama.
  • Komentar, ulasan, atau statistik yang tidak memengaruhi isi utama.
  • Bagian halaman yang bergantung ke API pihak ketiga yang responsnya tidak stabil.
  • Dashboard dengan beberapa widget independen yang bisa dimuat paralel.

Langkah Streaming Data di App Router

Ikuti pola ini: page induk tetap sinkron, hanya bagian lambat yang jadi komponen async.

1. Buat komponen async untuk bagian lambat, misalnya ProductList.tsx, dan lakukan fetch di dalamnya.
2. Di page.tsx, render konten utama secara langsung tanpa menunggu data lambat.
3. Bungkus komponen lambat dengan Suspense dan beri fallback.
4. Jalankan dan periksa fallback tampil dulu sebelum data masuk.

// app/products/page.tsx
import { Suspense } from "react";
import ProductList from "./ProductList";

export default function ProductsPage() {
  return (
    <main>
      <h1>Produk</h1>
      <Suspense fallback={<p>Memuat produk...</p>}>
        <ProductList />
      </Suspense>
    </main>
  );
}

// app/products/ProductList.tsx
export default async function ProductList() {
  const res = await fetch("https://api.example.com/products");
  const products = await res.json();

  return (
    <ul>
      {products.map((item) => (
        <li key={item.id}>{item.name}</li>
      ))}
    </ul>
  );
}

Tabel Pola Loading agar UI Tidak Patah

Pola Fungsi Catatan
Suspense per bagian Streaming tiap blok independen Jangan satu Suspense untuk semua
Skeleton Menjaga layout tetap stabil Samakan tinggi dengan konten asli
Parallel fetch Mengambil data sejajar Hindari await berurutan yang tidak perlu
  • Letakkan fallback sedekat mungkin dengan komponen yang di-streaming.
  • Gunakan skeleton dengan ukuran tetap agar tidak terjadi pergeseran layout.
  • Pisahkan Suspense untuk daftar, komentar, dan rekomendasi bila fetch-nya independen.
function ProductSkeleton() {
  return (
    <ul>
      {[1, 2, 3].map((i) => (
        <li key={i} style={{ height: 20, background: "#eee" }} />
      ))}
    </ul>
  );
}

FAQ

Apakah streaming sama dengan fetch di Client Component?

Tidak. Streaming tetap mengambil data di server, lalu HTML dikirim bertahap ke browser.

Kenapa fallback Suspense tidak muncul?

Biasanya fetch sudah selesai di server sebelum respons dikirim, atau posisi Suspense membungkus terlalu banyak konten.

Apakah streaming cocok untuk semua data?

Tidak. Data kritis above the fold sebaiknya dirender langsung agar SEO dan pengalaman baca tidak terganggu.