Navigasi Programmatic
Pindah halaman dari kode: useRouter, redirect, dan notFound.
Navigasi yang terjadi tanpa diklik
<Link> bekerja saat pengguna mengklik sesuatu. Tapi banyak perpindahan halaman terjadi karena kode, bukan klik: setelah login berhasil, aplikasi harus memindahkan pengguna ke dashboard. Setelah form tersimpan, pengguna dilempar ke halaman sukses. Setelah data dihapus, aplikasi kembali ke daftar.
Inilah navigasi programmatic: pindah halaman dari dalam kode. Next.js menyediakan tiga alat untuk tiga situasi berbeda, dan memilih yang salah adalah sumber bug yang umum.
Contoh 1: useRouter di Client Component
Untuk navigasi yang dipicu interaksi pengguna (klik tombol, submit form), pakai hook useRouter dari next/navigation:
// app/components/LoginButton.tsx
"use client";
import { useRouter } from "next/navigation";
export default function LoginButton() {
const router = useRouter();
async function handleLogin() {
const ok = await fakeLogin();
if (ok) {
router.push("/dashboard");
}
}
return <button onClick={handleLogin}>Masuk</button>;
}
async function fakeLogin() {
return true;
}Method yang tersedia:
router.push("/dashboard"): pindah dan menambah entry history (tombol back bisa kembali).router.replace("/dashboard"): pindah tanpa menambah history (seperti propreplacedi Link).router.back()danrouter.forward(): simulasi tombol back/forward browser.router.refresh(): memuat ulang data Server Component di halaman aktif tanpa pindah halaman, berguna setelah mutasi data supaya tampilan sinkron.
Dua hal wajib diingat: file harus diawali "use client" karena hook hanya jalan di client, dan import-nya dari next/navigation (App Router), bukan next/router (Pages Router lama yang sudah berbeda API).
Contoh 2: redirect() di Server Component
Untuk keputusan navigasi yang dibuat di server, misalnya proteksi halaman berdasarkan sesi login, pakai redirect():
// app/dashboard/page.tsx
import { redirect } from "next/navigation";
export default async function DashboardPage() {
const user = await getUser();
if (!user) {
redirect("/login");
}
return <h1>Halo, {user.name}</h1>;
}
async function getUser() {
return null;
}redirect() bekerja dengan melempar error khusus secara internal untuk menghentikan rendering, jadi panggil sebelum me-return JSX apa pun. Jangan bungkus dengan try/catch biasa karena blok catch akan menelan mekanisme redirect-nya dan halaman gagal pindah.
Kenapa tidak pakai useRouter di sini? Karena pengecekan auth terjadi di server sebelum halaman dikirim. Kalau menunggu sampai di client, pengguna yang belum login sempat melihat kilasan konten dashboard sebelum dipindahkan, itu celah UX sekaligus keamanan.
Contoh 3: notFound() untuk data yang tidak ada
// app/blog/[slug]/page.tsx
import { notFound } from "next/navigation";
export default async function BlogPost({
params,
}: {
params: Promise<{ slug: string }>;
}) {
const { slug } = await params;
const post = await getPost(slug);
if (!post) {
notFound();
}
return <article>{post.title}</article>;
}
async function getPost(slug: string) {
return slug === "hello" ? { title: "Halo" } : null;
}notFound() me-render file not-found.tsx terdekat. Ini jauh lebih elegan daripada me-return halaman kosong atau melempar error generik saat slug tidak punya data, dan status HTTP-nya benar 404 yang bagus untuk SEO.
Ringkasan pilihan alat: interaksi pengguna di client pakai
useRouter(push,replace,back,refresh), keputusan di server sebelum render pakairedirect(), data tidak ditemukan pakainotFound().redirectdannotFoundhanya untuk Server Component dan Route Handler, jangan dipakai di dalam event handler client.
Tantangan
Guard login
Buat halaman /dashboard yang me-redirect ke /login bila variabel isLoggedIn = false. Ubah ke true dan buktikan halaman tampil.
Kuis Bab
Uji pemahamanmu: Routing
Jawab 5 soal berikut, lalu tekan "Periksa Jawaban".
1.Folder app/blog/pertama/page.tsx menghasilkan URL apa?
2.Di Next.js 15+, bagaimana cara membaca params di page?
3.Apa fungsi folder (auth)?
4.Kenapa memakai <Link> bukan <a> untuk navigasi internal?
5.Fungsi notFound() adalah...