Fetch di Server Component
Pola dasar: async component + fetch langsung tanpa useEffect.
Fetch langsung di Server Component: pola paling sederhana
Bayangkan sebuah restoran. Di pola lama (React SPA), pelayan (browser) harus bolak-balik ke pasar (API) setiap kali tamu memesan: ambil bahan, kembali, baru masak, baru hidang. Tamu menunggu lama dan melihat dapur yang kosong dulu (loading spinner). Di Next.js App Router, juru masak (server) mengambil bahan sendiri dari pasar SEBELUM tamu duduk. Saat hidangan sampai ke meja, semuanya sudah siap.
Itulah kenapa pola ini ada. Di era useEffect, setiap halaman mengambil datanya di browser: JavaScript dimuat dulu, efek berjalan, request dikirim, loading tampil, data datang, baru render. Tiga masalah muncul: pengguna melihat layar kosong atau loading, mesin pencari (crawler) sering hanya melihat kerangka kosong sehingga SEO jeblok, dan API key yang dipakai di client bisa diintip siapa saja lewat DevTools.
Server Component membalik alurnya. Komponen page.tsx boleh async, dan await fetch() di dalamnya berjalan di server, sebelum satu byte HTML pun dikirim ke browser. Hasilnya: HTML yang sampai sudah berisi data lengkap.
// app/users/page.tsx
export default async function Users() {
const res = await fetch("https://jsonplaceholder.typicode.com/users");
if (!res.ok) throw new Error("Gagal memuat daftar user");
const users: { id: number; name: string }[] = await res.json();
return (
<ul>
{users.map((u) => (
<li key={u.id}>{u.name}</li>
))}
</ul>
);
}Perhatikan betapa datarnya kode ini: tidak ada useState, tidak ada useEffect, tidak ada state loading. Komponennya async seperti fungsi biasa, dan itu legal hanya di Server Component.
Contoh kedua: halaman yang datanya harus selalu segar, misalnya daftar harga atau stok. Secara default fetch di Server Component di-cache (dibahas tuntas di modul caching), jadi untuk data real-time tambahkan cache: "no-store":
// app/stok/page.tsx
export default async function Stok() {
const res = await fetch("https://api.example.com/stok", {
cache: "no-store", // selalu ambil data terbaru
});
const items = await res.json();
return <StockTable items={items} />;
}Kenapa tanpa useEffect?
Karena fetch-nya terjadi di server sebelum HTML dikirim: tidak ada loading state manual (Next.js menanganinya lewat Suspense otomatis), tidak ada waterfall di client, dan SEO mendapat konten penuh karena crawler menerima HTML yang sudah jadi. Bonus keamanan: API key atau database credential yang dipakai di sini tidak pernah sampai ke browser.
Perbandingan singkat
| Server fetch | useEffect fetch | |
|---|---|---|
| Loading state | Otomatis (Suspense) | Ditulis manual |
| SEO | Konten penuh saat crawl | Sering kosong saat crawl |
| Secret/API key | Aman di server | Terlihat di browser |
Aturan main: pola
async+await fetchhanya untuk Server Component. Kalau komponenmu butuh interaktivitas (onClick,useState), ia adalah Client Component, dan fetch di sana dibahas di modul fetch-client-component. Jangan campur: fetch data awal di server, interaksi di client.
Tantangan
Daftar user
Buat halaman /users yang fetch 10 user dari jsonplaceholder langsung di Server Component. Matikan JavaScript di browser dan buktikan daftar tetap tampil.