Bungkus komponen async yang lambat dengan <Suspense fallback={...}> agar bagian lain halaman langsung tampil. Next.js App Router akan melakukan streaming, jadi pengguna melihat konten cepat lebih dulu sementara komponen lambat menyusul tanpa memblokir seluruh page.
Hasil Akhir Cara Menggunakan Suspense di App Router
Pola yang benar adalah streaming per bagian halaman. Header, navigasi, dan konten statis dirender dulu. Hanya blok yang menunggu fetch data yang diganti fallback sementara.
Komponen yang dibungkus harus tetap Server Component. Biarkan async untuk fetch di server dan jangan tambah "use client" kecuali butuh interaksi browser.
// app/dashboard/page.tsx
import { Suspense } from "react";
import StatsLambat from "./stats-lambat";
export default function Page() {
return (
<main>
<h1>Dashboard</h1>
<Suspense fallback={<p>Memuat statistik...</p>}>
<StatsLambat />
</Suspense>
</main>
);
}
Langkah Memasang Suspense untuk Server Component
1. Buat komponen async untuk fetch data di server. Pisahkan query lambat ke file sendiri agar boundary Suspense jelas.
// app/dashboard/stats-lambat.tsx
export default async function StatsLambat() {
const res = await fetch("https://api.example.com/stats");
const data = await res.json();
return <p>Total: {data.total}</p>;
}
2. Bungkus komponen dengan <Suspense fallback={...}> di page atau layout. Import Suspense dari react, bukan dari Next.js.
3. Pisahkan bagian lambat dan cepat agar tidak saling menunggu. Letakkan konten cepat di luar Suspense. Satu fetch lambat tidak boleh menahan seluruh halaman.
- Gunakan fallback kecil dan spesifik, misalnya skeleton untuk kartu tersebut saja.
- Jangan menaruh fetch cepat dan lambat dalam satu komponen async yang sama.
- Letakkan Suspense sedekat mungkin dengan komponen lambatnya.
Pola yang Sering Dipakai dan Kesalahan Umum
| Pola | Fungsi | Catatan |
|---|---|---|
| Suspense tunggal | Menangani satu widget lambat | Cocok untuk statistik atau daftar tambahan |
| Suspense bersarang | Fallback bertingkat parent dan child | Child bisa tampil walau parent masih streaming |
| Suspense paralel | Beberapa boundary sejajar | Tiap bagian selesai tanpa menunggu yang lain |
Jangan bungkus seluruh page jika hanya satu widget yang lambat. Fallback selebar layar membuat streaming tidak ada gunanya.
Jangan panggil hook seperti useState atau event handler seperti onClick di dalam Server Component async. Pindahkan logika interaktif ke Client Component terpisah.
- Fallback terlalu besar sehingga halaman terlihat loading semua.
- Fetch berantai di satu komponen, seharusnya dibuat paralel.
- Mencampur logika client ke Server Component async lalu error saat build.
FAQ
Apakah Suspense bisa dipakai tanpa fetch async?
Bisa, misalnya untuk komponen server yang menunggu operasi lambat seperti membaca file, selama komponen tersebut suspend.
Kenapa fallback Suspense tidak muncul?
Umumnya karena komponen tidak benar-benar async atau datanya sudah tersedia dari cache sehingga selesai instan.
Kapan memakai loading.js dibanding Suspense?
Pakai loading.js untuk loading level route, pakai Suspense untuk loading granular per komponen dalam satu halaman.