nextjsfetchpatternMahir4 mnt baca

Pola Fetch Lanjutan

Rangkuman pola: fetch di layout, helper terpusat, dan error handling.

Dari pola ke sistem

Bayangkan dapur restoran yang sudah besar. Tidak cukup hanya tahu cara memasak satu hidangan, butuh sistem: buku resep standar supaya semua koki meracik bumbu yang sama, juru masak shift pagi yang menyiapkan bahan dasar untuk semua menu hari itu, dan prosedur jelas saat bahan habis. Modul ini merangkum tiga pola lanjutan yang mengubah fetch acak menjadi sistem yang rapi: helper terpusat, fetch di layout, dan error handling yang konsisten.

Kenapa ini penting? Di proyek kecil, fetch langsung di page tidak masalah. Di proyek besar, URL yang tersebar di 20 file berarti mengubah base URL API harus menyentuh 20 file. Data navigasi yang di-fetch ulang di tiap page berarti request mubazir. Error yang di-silent dengan return null berarti bug yang tidak terlacak. Tiga pola ini menyelesaikan ketiganya.

Helper terpusat: satu buku resep

ts
// lib/api.ts
// Contoh 1: semua akses API lewat sini, bukan URL mentah di tiap file
const BASE = "https://api.example.com";

export async function getPosts() {
  const res = await fetch(`${BASE}/posts`, {
    next: { revalidate: 60 },
  });
  if (!res.ok) throw new Error("Gagal memuat posts");
  return res.json();
}

export async function getCategories() {
  const res = await fetch(`${BASE}/categories`);
  if (!res.ok) throw new Error("Gagal memuat kategori");
  return res.json();
}

Satu fungsi per resource, opsi cache dan revalidate terpusat di satu tempat. Butuh ganti base URL, tambah header auth, atau ubah strategi cache? Satu file saja yang disentuh. Bonusnya: karena semua komponen memakai helper yang sama dengan URL dan opsi identik, request memoization bekerja maksimal dan duplikasi request hilang sendiri.

Fetch di layout: siapkan bahan dasar sekali

tsx
// app/blog/layout.tsx
// Contoh 2: layout boleh async, cocok untuk data yang dipakai
// semua halaman di segmen ini (mis. navigasi kategori)
import { getCategories } from "@/lib/api";

export default async function BlogLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  const cats = await getCategories();

  return (
    <div className="flex">
      <aside>
        {cats.map((c: { id: number; name: string }) => (
          <a key={c.id} href={`/blog/kategori/${c.id}`}>
            {c.name}
          </a>
        ))}
      </aside>
      <main>{children}</main>
    </div>
  );
}

Data kategori di-fetch sekali di layout, lalu semua halaman /blog/* tinggal memakai. Tanpa pola ini, tiap page harus fetch kategori sendiri-sendiri. Ingat: layout tidak re-render saat navigasi antar page dalam segmen yang sama, jadi fetch di layout juga menghemat request saat user berpindah halaman.

Error handling: jangan bungkam error

Fetch yang gagal di Server Component akan melempar ke error.tsx terdekat, itu perilaku yang diinginkan. Maka aturannya: selalu throw dengan pesan yang jelas, jangan pernah return null diam-diam. return null membuat halaman tampil kosong tanpa penjelasan, dan kamu baru sadar ada masalah saat user komplain. throw new Error("Gagal memuat posts") membuat error.tsx menampilkan pesan yang bisa di-debug, lengkap dengan tombol coba lagi.

Catatan teknis: Pola ideal yang menutup 95% kebutuhan data fetching terdiri dari empat pilar: helper di lib/ (satu sumber kebenaran untuk akses API), fetch di server (page untuk data halaman, layout untuk data bersama), loading via Suspense/loading.tsx (jangan tulis spinner manual), dan error via error.tsx (throw dengan pesan jelas). Kalau keempatnya sudah jadi kebiasaan, data fetching di aplikasimu praktis tidak punya kejutan lagi.

Tantangan

Refactor helper

Refactor halaman yang fetch langsung di 3 tempat menjadi memakai satu helper lib/api.ts. Pastikan perilaku sama dan tidak ada duplikasi URL.

Kuis Bab

Uji pemahamanmu: Data Fetching

Jawab 5 soal berikut, lalu tekan "Periksa Jawaban".

1.Kenapa fetch di Server Component lebih baik untuk SEO?

2.Bagaimana cara fetch dua API independen dengan cepat?

3.Apa arti cache: "no-store" pada fetch?

4.Apa itu ISR (Incremental Static Regeneration)?

5.Kapan fetch di Client Component dibenarkan?