Episode ini membedah data fetching di App Router: fetch server-side dengan async server components, static generation memakai generateStaticParams, Incremental Static Regeneration dengan revalidate, dan route handler untuk membangun backend API.

Sebuah aplikasi nyata membutuhkan data. Pertanyaan kuncinya bukan hanya bagaimana mengambil data, tapi kapan dan di mana — di server saat build, di server setiap request, atau di klien setelah halaman dimuat. Episode 6 menjawab pertanyaan itu.
Kita akan membahas pengambilan data server-side di App Router, static generation dengan generateStaticParams, Incremental Static Regeneration (ISR) dengan revalidate, serta route handler untuk membangun backend API sederhana.
Di App Router, server component bisa bersifat async dan memakai fetch langsung:
export default async function Posts() {
const res = await fetch("https://jsonplaceholder.typicode.com/posts")
const posts = await res.json()
return (
<ul>
{posts.slice(0, 5).map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
)
}Fetch langsung di dalam komponen server di atas berjalan di server, tanpa memuat berlebih ke klien. Key dalam list rendering di episode 0 — key={post.id} — menghindari peringatan React saat list di-render.
Fungsi fetch bawaan Next.js mendukung caching dan revalidation berbasis waktu:
const res = await fetch("https://api.example.com/products", {
next: { revalidate: 3600 },
})Opsi next: { revalidate: 3600 } membuat data di-cache dan di-refresh di background setiap satu jam. Inilah mekanisme dasar Incremental Static Regeneration.
Untuk halaman dinamis yang datanya jarang berubah, kombinasikan generateStaticParams dengan mode statis. Semua halaman dibangun saat npm run build:
export async function generateStaticParams() {
const res = await fetch("https://api.example.com/articles")
const articles = await res.json()
return articles.map((a) => ({ slug: a.slug }))
}
export default async function Article({ params }) {
const { slug } = await params
const res = await fetch(`https://api.example.com/articles/${slug}`)
const article = await res.json()
return <h1>{article.title}</h1>
}Semua slug artikel terdaftar di generateStaticParams dan di-prerender saat build. Halaman yang tidak terdaftar akan otomatis menampilkan 404 — kecuali opsi dynamicParams diaktifkan.
ISR memungkinkan halaman statis tetap diperbarui. Ada dua cara memicu revalidation: berbasis waktu dengan next: { revalidate: 60 }, atau on-demand dengan memanggil API:
import { revalidatePath } from "next/cache"
export async function POST(request) {
await request.json()
revalidatePath("/articles")
return new Response("Cache dibersihkan", { status: 200 })
}revalidatePath("/articles") memaksa halaman /articles dibangun ulang saat endpoint di atas dipanggil. Pola ini berguna setelah data di CMS diperbarui, tanpa menunggu jendela waktu.
App Router membangun API lewat file route.ts yang mengekspor handler berdasarkan metode HTTP. Buat app/api/items/route.ts:
import { NextResponse } from "next/server"
export async function GET() {
return NextResponse.json({ items: ["apel", "mangga"] })
}
export async function POST(request) {
const body = await request.json()
return NextResponse.json({ created: body }, { status: 201 })
}Endpoint di atas tersedia di /api/items. NextResponse.json menyederhanakan respons JSON, dan status 201 menandakan resource berhasil dibuat. Route handler ini adalah pondasi backend API Next.js yang akan kita amankan di episode 13.
Inti yang harus dibawa pulang:
Di episode 7 selanjutnya kita akan membahas state management dan hooks — state lokal dengan hooks React, direktif use client dan batas server-client, shared state dengan Context API, Zustand, dan TanStack Query, serta lifecycle komponen klien versus komponen server. Interaktivitas aplikasi kalian mulai dibangun.