Bahasa Indonesia

Maksimalkan kekuatan App Router Next.js dengan panduan mendalam kami tentang perutean berbasis file. Pelajari cara menyusun aplikasi Anda, membuat rute dinamis, menangani layout, dan banyak lagi.

App Router Next.js: Panduan Komprehensif untuk Perutean Berbasis File

App Router Next.js, yang diperkenalkan di Next.js 13 dan menjadi standar di versi-versi selanjutnya, merevolusi cara kita menyusun dan menavigasi aplikasi. Ini memperkenalkan sistem perutean berbasis file yang kuat dan intuitif yang menyederhanakan pengembangan, meningkatkan performa, dan menyempurnakan pengalaman pengembang secara keseluruhan. Panduan komprehensif ini akan membahas secara mendalam perutean berbasis file App Router, memberikan Anda pengetahuan dan keterampilan untuk membangun aplikasi Next.js yang tangguh dan skalabel.

Apa itu Perutean Berbasis File?

Perutean berbasis file adalah sistem perutean di mana struktur rute aplikasi Anda ditentukan secara langsung oleh organisasi file dan direktori Anda. Di App Router Next.js, Anda mendefinisikan rute dengan membuat file di dalam direktori `app`. Setiap folder mewakili segmen rute, dan file khusus di dalam folder tersebut mendefinisikan bagaimana segmen rute itu akan ditangani. Pendekatan ini menawarkan beberapa keuntungan:

Memulai dengan App Router

Untuk menggunakan App Router, Anda perlu membuat proyek Next.js baru atau memigrasikan proyek yang sudah ada. Pastikan Anda menggunakan Next.js versi 13 atau lebih baru.

Membuat Proyek Baru:

Anda dapat membuat proyek Next.js baru dengan App Router menggunakan perintah berikut:

npx create-next-app@latest my-app --example with-app

Memigrasikan Proyek yang Ada:

Untuk memigrasikan proyek yang sudah ada, Anda perlu memindahkan halaman Anda dari direktori `pages` ke direktori `app`. Anda mungkin perlu menyesuaikan logika perutean Anda. Next.js menyediakan panduan migrasi untuk membantu Anda dalam proses ini.

Konsep Inti Perutean Berbasis File

App Router memperkenalkan beberapa file dan konvensi khusus yang mendefinisikan bagaimana rute Anda ditangani:

1. Direktori `app`

Direktori `app` adalah akar dari rute aplikasi Anda. Semua file dan folder di dalam direktori ini akan digunakan untuk menghasilkan rute. Apa pun di luar direktori `app` (seperti direktori `pages` jika Anda sedang migrasi) akan diabaikan oleh App Router.

2. File `page.js`

File `page.js` (atau `page.jsx`, `page.ts`, `page.tsx`) adalah bagian paling fundamental dari App Router. Ini mendefinisikan komponen UI yang akan dirender untuk segmen rute tertentu. Ini adalah file wajib untuk setiap segmen rute yang ingin Anda akses secara langsung.

Contoh:

Jika Anda memiliki struktur file seperti ini:

app/
  about/
    page.js

Komponen yang diekspor dari `app/about/page.js` akan dirender ketika pengguna menavigasi ke `/about`.

// app/about/page.js
import React from 'react';

export default function AboutPage() {
  return (
    <div>
      <h1>Tentang Kami</h1>
      <p>Pelajari lebih lanjut tentang perusahaan kami.</p>
    </div>
  );
}

3. File `layout.js`

File `layout.js` (atau `layout.jsx`, `layout.ts`, `layout.tsx`) mendefinisikan UI yang dibagikan di beberapa halaman dalam segmen rute. Layout berguna untuk membuat header, footer, sidebar, dan elemen lain yang konsisten yang harus ada di beberapa halaman.

Contoh:

Katakanlah Anda ingin menambahkan header ke halaman `/about` dan halaman hipotetis `/about/team`. Anda dapat membuat file `layout.js` di direktori `app/about`:

// app/about/layout.js
import React from 'react';

export default function AboutLayout({ children }) {
  return (
    <div>
      <header>
        <h1>Tentang Perusahaan Kami</h1>
      </header>
      <main>{children}</main>
    </div>
  );
}

Prop `children` akan digantikan dengan UI yang dirender oleh file `page.js` di direktori yang sama atau di direktori bersarang mana pun.

4. File `template.js`

File `template.js` mirip dengan `layout.js`, tetapi ia membuat instance baru dari komponen untuk setiap rute anak. Ini berguna untuk skenario di mana Anda ingin mempertahankan state komponen atau mencegah render ulang saat menavigasi antar rute anak. Tidak seperti layout, template akan dirender ulang saat navigasi. Menggunakan template sangat bagus untuk menganimasikan elemen saat navigasi.

Contoh:

// app/template.js
'use client'

import { useState } from 'react'

export default function Template({ children }) {
  const [count, setCount] = useState(0)

  return (
    <main>
      <p>Template: {count}</p>
      <button onClick={() => setCount(count + 1)}>Perbarui Template</button>
      {children}
    </main>
  )
}

5. File `loading.js`

File `loading.js` (atau `loading.jsx`, `loading.ts`, `loading.tsx`) memungkinkan Anda membuat UI pemuatan yang ditampilkan saat segmen rute sedang dimuat. Ini berguna untuk memberikan pengalaman pengguna yang lebih baik saat mengambil data atau melakukan operasi asinkron lainnya.

Contoh:

// app/about/loading.js
import React from 'react';

export default function Loading() {
  return <p>Memuat informasi tentang...</p>;
}

Ketika pengguna menavigasi ke `/about`, komponen `Loading` akan ditampilkan hingga komponen `page.js` sepenuhnya dirender.

6. File `error.js`

File `error.js` (atau `error.jsx`, `error.ts`, `error.tsx`) memungkinkan Anda membuat UI kesalahan kustom yang ditampilkan ketika terjadi kesalahan dalam segmen rute. Ini berguna untuk memberikan pesan kesalahan yang lebih ramah pengguna dan mencegah seluruh aplikasi mogok.

Contoh:

// app/about/error.js
'use client'

import React from 'react';

export default function Error({ error, reset }) {
  return (
    <div>
      <h2>Terjadi kesalahan!</h2>
      <p>{error.message}</p>
      <button onClick={() => reset()}>Coba lagi</button>
    </div>
  );
}

Jika terjadi kesalahan saat merender halaman `/about`, komponen `Error` akan ditampilkan. Prop `error` berisi informasi tentang kesalahan tersebut, dan fungsi `reset` memungkinkan pengguna untuk mencoba memuat ulang halaman.

7. Grup Rute

Grup Rute `(namaGrup)` memungkinkan Anda untuk mengatur rute Anda tanpa mempengaruhi struktur URL. Mereka dibuat dengan membungkus nama folder dalam tanda kurung. Ini sangat membantu untuk mengatur layout dan komponen bersama.

Contoh:

app/
  (marketing)/
    about/
      page.js
    contact/
      page.js
  (shop)/
    products/
      page.js

Dalam contoh ini, halaman `about` dan `contact` dikelompokkan di bawah grup `marketing`, dan halaman `products` berada di bawah grup `shop`. URL tetap `/about`, `/contact`, dan `/products`.

8. Rute Dinamis

Rute dinamis memungkinkan Anda membuat rute dengan segmen variabel. Ini berguna untuk menampilkan konten berdasarkan data yang diambil dari database atau API. Segmen rute dinamis didefinisikan dengan membungkus nama segmen dalam kurung siku (misalnya, `[id]`).

Contoh:

Katakanlah Anda ingin membuat rute untuk menampilkan posting blog individu berdasarkan ID mereka. Anda dapat membuat struktur file seperti ini:

app/
  blog/
    [id]/
      page.js

Segmen `[id]` adalah segmen dinamis. Komponen yang diekspor dari `app/blog/[id]/page.js` akan dirender ketika pengguna menavigasi ke URL seperti `/blog/123` atau `/blog/456`. Nilai parameter `id` akan tersedia di prop `params` dari komponen.

// app/blog/[id]/page.js
import React from 'react';

export default async function BlogPost({ params }) {
  const { id } = params;

  // Ambil data untuk posting blog dengan ID yang diberikan
  const post = await fetchBlogPost(id);

  if (!post) {
    return <p>Postingan blog tidak ditemukan.</p>;
  }

  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.content}</p>
    </div>
  );
}

async function fetchBlogPost(id) {
  // Mensimulasikan pengambilan data dari database atau API
  return new Promise((resolve) => {
    setTimeout(() => {
      const posts = {
        '123': { title: 'Postingan Blog Pertama Saya', content: 'Ini adalah konten postingan blog pertama saya.' },
        '456': { title: 'Postingan Blog Lain', content: 'Ini adalah beberapa konten menarik lainnya.' },
      };
      resolve(posts[id] || null);
    }, 500);
  });
}

Anda juga dapat menggunakan beberapa segmen dinamis dalam satu rute. Misalnya, Anda bisa memiliki rute seperti `/blog/[category]/[id]`.

9. Segmen Catch-all

Segmen catch-all memungkinkan Anda membuat rute yang cocok dengan sejumlah segmen. Ini berguna untuk skenario seperti membuat CMS di mana struktur URL ditentukan oleh pengguna. Segmen catch-all didefinisikan dengan menambahkan tiga titik sebelum nama segmen (misalnya, `[...slug]`).

Contoh:

app/
  docs/
    [...slug]/
      page.js

Segmen `[...slug]` akan cocok dengan sejumlah segmen setelah `/docs`. Misalnya, ini akan cocok dengan `/docs/getting-started`, `/docs/api/users`, dan `/docs/advanced/configuration`. Nilai parameter `slug` akan menjadi array yang berisi segmen yang cocok.

// app/docs/[...slug]/page.js
import React from 'react';

export default function DocsPage({ params }) {
  const { slug } = params;

  return (
    <div>
      <h1>Dokumen</h1>
      <p>Slug: {slug ? slug.join('/') : 'Tidak ada slug'}</p>
    </div>
  );
}

Segmen catch-all opsional dapat dibuat dengan menambahkan nama segmen dalam kurung siku ganda `[[...slug]]`. Ini membuat segmen rute menjadi opsional. Contoh:

app/
  blog/
    [[...slug]]/
      page.js

Pengaturan ini akan merender komponen page.js baik di `/blog` maupun di `/blog/any/number/of/segments`.

10. Rute Paralel

Rute Paralel memungkinkan Anda untuk merender satu atau lebih halaman secara bersamaan dalam layout yang sama. Ini sangat berguna untuk layout yang kompleks, seperti dasbor, di mana bagian-bagian berbeda dari halaman dapat dimuat secara independen. Rute Paralel didefinisikan menggunakan simbol `@` diikuti dengan nama slot (misalnya, `@sidebar`, `@main`).

Contoh:

app/
  @sidebar/
    page.js  // Konten untuk sidebar
  @main/
    page.js  // Konten untuk bagian utama
  default.js // Diperlukan: Mendefinisikan layout default untuk rute paralel

File `default.js` diperlukan saat menggunakan rute paralel. Ini mendefinisikan bagaimana slot-slot yang berbeda digabungkan untuk membuat layout akhir.

// app/default.js
export default function RootLayout({ children: { sidebar, main } }) {
  return (
    <div style={{ display: 'flex' }}>
      <aside style={{ width: '200px', backgroundColor: '#f0f0f0' }}>
        {sidebar}
      </aside>
      <main style={{ flex: 1, padding: '20px' }}>
        {main}
      </main>
    </div>
  );
}

11. Rute Intersepsi

Rute Intersepsi memungkinkan Anda memuat rute dari bagian lain aplikasi Anda dalam layout saat ini. Ini berguna untuk membuat modal, galeri gambar, dan elemen UI lainnya yang seharusnya muncul di atas konten halaman yang ada. Rute Intersepsi didefinisikan menggunakan sintaks `(..)` , yang menunjukkan berapa banyak level ke atas pohon direktori untuk menemukan rute yang diintersepsi.

Contoh:

app/
  (.)photos/
    [id]/
      page.js  // Rute yang diintersepsi
  feed/
    page.js  // Halaman tempat modal foto ditampilkan

Dalam contoh ini, ketika pengguna mengklik foto di halaman `/feed`, rute `app/(.)photos/[id]/page.js` diintersepsi dan ditampilkan sebagai modal di atas halaman `/feed`. Sintaks `(.)` memberitahu Next.js untuk mencari satu level ke atas (ke direktori `app`) untuk menemukan rute `photos/[id]`.

Pengambilan Data dengan App Router

App Router menyediakan dukungan bawaan untuk pengambilan data menggunakan Komponen Server dan Komponen Klien. Komponen Server dirender di server, sedangkan Komponen Klien dirender di klien. Ini memungkinkan Anda memilih pendekatan terbaik untuk setiap komponen berdasarkan kebutuhannya.

Komponen Server

Komponen Server adalah default di App Router. Mereka memungkinkan Anda untuk mengambil data langsung di komponen Anda tanpa perlu rute API terpisah. Ini dapat meningkatkan kinerja dan menyederhanakan kode Anda.

Contoh:

// app/products/page.js
import React from 'react';

export default async function ProductsPage() {
  const products = await fetchProducts();

  return (
    <div>
      <h1>Produk</h1>
      <ul>
        {products.map((product) => (
          <li key={product.id}>{product.name}</li>
        ))}
      </ul>
    </div>
  );
}

async function fetchProducts() {
  // Mensimulasikan pengambilan data dari database atau API
  return new Promise((resolve) => {
    setTimeout(() => {
      const products = [
        { id: 1, name: 'Produk A' },
        { id: 2, name: 'Produk B' },
        { id: 3, name: 'Produk C' },
      ];
      resolve(products);
    }, 500);
  });
}

Dalam contoh ini, fungsi `fetchProducts` dipanggil langsung di dalam komponen `ProductsPage`. Komponen dirender di server, dan data diambil sebelum HTML dikirim ke klien.

Komponen Klien

Komponen Klien dirender di klien dan memungkinkan Anda menggunakan fitur sisi klien seperti event listener, state, dan API browser. Untuk menggunakan Komponen Klien, Anda perlu menambahkan direktif `'use client'` di bagian atas file.

Contoh:

// app/counter/page.js
'use client'

import React, { useState } from 'react';

export default function CounterPage() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <h1>Penghitung</h1>
      <p>Jumlah: {count}</p>
      <button onClick={() => setCount(count + 1)}>Tambah</button>
    </div>
  );
}

Dalam contoh ini, komponen `CounterPage` adalah Komponen Klien karena menggunakan hook `useState`. Direktif `'use client'` memberitahu Next.js untuk merender komponen ini di klien.

Teknik Perutean Lanjutan

App Router menawarkan beberapa teknik perutean lanjutan yang dapat digunakan untuk membuat aplikasi yang kompleks dan canggih.

1. Penangan Rute

Penangan Rute memungkinkan Anda membuat endpoint API di dalam direktori `app` Anda. Ini menghilangkan kebutuhan untuk direktori `pages/api` terpisah. Penangan Rute didefinisikan dalam file bernama `route.js` (atau `route.ts`) dan mengekspor fungsi yang menangani metode HTTP yang berbeda (misalnya, `GET`, `POST`, `PUT`, `DELETE`).

Contoh:

// app/api/users/route.js
import { NextResponse } from 'next/server'

export async function GET(request) {
  // Mensimulasikan pengambilan pengguna dari database
  const users = [
    { id: 1, name: 'John Doe' },
    { id: 2, name: 'Jane Doe' },
  ];

  return NextResponse.json(users);
}

export async function POST(request) {
  const body = await request.json()
  console.log('Data diterima:', body)
  return NextResponse.json({ message: 'Pengguna dibuat' }, { status: 201 })
}

Contoh ini mendefinisikan penangan rute di `/api/users` yang menangani permintaan `GET` dan `POST`. Fungsi `GET` mengembalikan daftar pengguna, dan fungsi `POST` membuat pengguna baru.

2. Grup Rute dengan Beberapa Layout

Anda dapat menggabungkan grup rute dengan layout untuk membuat layout yang berbeda untuk bagian yang berbeda dari aplikasi Anda. Ini berguna untuk skenario di mana Anda ingin memiliki header atau sidebar yang berbeda untuk bagian yang berbeda dari situs Anda.

Contoh:

app/
  (marketing)/
    layout.js  // Layout marketing
    about/
      page.js
    contact/
      page.js
  (admin)/
    layout.js  // Layout admin
    dashboard/
      page.js

Dalam contoh ini, halaman `about` dan `contact` akan menggunakan layout `marketing`, sedangkan halaman `dashboard` akan menggunakan layout `admin`.

3. Middleware

Middleware memungkinkan Anda menjalankan kode sebelum permintaan ditangani oleh aplikasi Anda. Ini berguna untuk tugas-tugas seperti otentikasi, otorisasi, pencatatan log, dan mengarahkan pengguna berdasarkan lokasi atau perangkat mereka.

Middleware didefinisikan dalam file bernama `middleware.js` (atau `middleware.ts`) di root proyek Anda.

Contoh:

// middleware.js
import { NextResponse } from 'next/server'

export function middleware(request) {
  // Periksa apakah pengguna terotentikasi
  const isAuthenticated = false; // Ganti dengan logika otentikasi Anda

  if (!isAuthenticated && request.nextUrl.pathname.startsWith('/admin')) {
    return NextResponse.redirect(new URL('/login', request.url));
  }

  return NextResponse.next();
}

// Lihat "Matching Paths" di bawah untuk mempelajari lebih lanjut
export const config = {
  matcher: '/admin/:path*',
}

Contoh ini mendefinisikan middleware yang memeriksa apakah pengguna terotentikasi sebelum mengizinkan mereka mengakses rute apa pun di bawah `/admin`. Jika pengguna tidak terotentikasi, mereka diarahkan ke halaman `/login`.

Praktik Terbaik untuk Perutean Berbasis File

Untuk memanfaatkan sistem perutean berbasis file App Router secara maksimal, pertimbangkan praktik terbaik berikut:

Contoh Internasionalisasi dengan App Router Next.js

App Router Next.js menyederhanakan internasionalisasi (i18n) melalui perutean berbasis file. Berikut adalah cara Anda dapat mengimplementasikan i18n secara efektif:

1. Perutean Sub-path

Atur rute Anda berdasarkan lokal menggunakan sub-path. Contohnya:

app/
  [locale]/
    page.tsx         // Halaman beranda untuk lokal
    about/
      page.tsx     // Halaman tentang untuk lokal
// app/[locale]/page.tsx
import { getTranslations } from './dictionaries';

export default async function HomePage({ params: { locale } }) {
  const t = await getTranslations(locale);
  return (<h1>{t.home.title}</h1>);
}

// dictionaries.js
const dictionaries = {
  en: () => import('./dictionaries/en.json').then((module) => module.default),
  id: () => import('./dictionaries/id.json').then((module) => module.default),
};

export const getTranslations = async (locale) => {
  try {
    return dictionaries[locale]() ?? dictionaries.en();
  } catch (error) {
    console.error(`Gagal memuat terjemahan untuk lokal ${locale}`, error);
    return dictionaries.en();
  }
};

Dalam pengaturan ini, segmen rute dinamis `[locale]` menangani berbagai lokal (misalnya, `/en`, `/id`). Terjemahan dimuat secara dinamis berdasarkan lokal.

2. Perutean Domain

Untuk pendekatan yang lebih canggih, Anda dapat menggunakan domain atau subdomain yang berbeda untuk setiap lokal. Ini sering melibatkan konfigurasi tambahan dengan penyedia hosting Anda.

3. Middleware untuk Deteksi Lokal

Gunakan middleware untuk secara otomatis mendeteksi lokal pilihan pengguna dan mengarahkan mereka sesuai.

// middleware.js
import { NextResponse } from 'next/server';
import { match } from '@formatjs/intl-localematcher';
import Negotiator from 'negotiator';

let locales = ['en', 'id', 'fr'];

function getLocale(request) {
  const negotiatorHeaders = {};
  request.headers.forEach((value, key) => (negotiatorHeaders[key] = value));
  let languages = new Negotiator({ headers: negotiatorHeaders }).languages();

  try {
      return match(languages, locales, 'en'); // Gunakan "en" sebagai lokal default
  } catch (error) {
      console.error("Error mencocokkan lokal:", error);
      return 'en'; // Kembali ke Bahasa Inggris jika pencocokan gagal
  }
}

export function middleware(request) {
  const pathname = request.nextUrl.pathname;
  const pathnameIsMissingLocale = locales.every(
    (locale) => !pathname.startsWith(`/${locale}/`) && pathname !== `/${locale}`
  );

  if (pathnameIsMissingLocale) {
    const locale = getLocale(request);

    return NextResponse.redirect(
      new URL(
        `/${locale}${pathname.startsWith('/') ? '' : '/'}${pathname}`,
        request.url
      )
    );
  }
}

export const config = {
  matcher: [
    '/((?!api|_next/static|_next/image|favicon.ico).*)',
  ],
};

Middleware ini memeriksa apakah path yang diminta memiliki awalan lokal. Jika tidak, ia mendeteksi lokal pilihan pengguna menggunakan header `Accept-Language` dan mengarahkan mereka ke path spesifik lokal yang sesuai. Pustaka seperti `@formatjs/intl-localematcher` dan `negotiator` digunakan untuk menangani negosiasi lokal.

App Router Next.js dan Aksesibilitas Global

Menciptakan aplikasi web yang dapat diakses secara global memerlukan pertimbangan cermat terhadap prinsip-prinsip aksesibilitas (a11y). App Router Next.js menyediakan fondasi yang kokoh untuk membangun pengalaman yang dapat diakses, tetapi penting untuk menerapkan praktik terbaik untuk memastikan aplikasi Anda dapat digunakan oleh semua orang, terlepas dari kemampuan mereka.

Pertimbangan Aksesibilitas Utama

  1. HTML Semantik: Gunakan elemen HTML semantik (misalnya, `<article>`, `<nav>`, `<aside>`, `<main>`) untuk menyusun konten Anda. Ini memberikan makna pada teknologi bantu dan membantu pengguna menavigasi situs Anda dengan lebih mudah.
  2. Atribut ARIA: Gunakan atribut ARIA (Accessible Rich Internet Applications) untuk meningkatkan aksesibilitas komponen dan widget kustom. Atribut ARIA memberikan informasi tambahan tentang peran, status, dan properti elemen ke teknologi bantu.
  3. Navigasi Keyboard: Pastikan semua elemen interaktif dapat diakses melalui keyboard. Pengguna harus dapat menavigasi melalui aplikasi Anda menggunakan tombol `Tab` dan berinteraksi dengan elemen menggunakan tombol `Enter` atau `Space`.
  4. Kontras Warna: Gunakan kontras warna yang cukup antara teks dan latar belakang untuk memastikan keterbacaan bagi pengguna dengan gangguan penglihatan. Web Content Accessibility Guidelines (WCAG) merekomendasikan rasio kontras setidaknya 4.5:1 untuk teks normal dan 3:1 untuk teks besar.
  5. Teks Alt Gambar: Sediakan teks alt deskriptif untuk semua gambar. Teks alt menyediakan alternatif teks untuk gambar yang dapat dibaca oleh pembaca layar.
  6. Label Formulir: Kaitkan label formulir dengan bidang input yang sesuai menggunakan elemen `<label>`. Ini membuat jelas bagi pengguna informasi apa yang diharapkan di setiap bidang.
  7. Pengujian Pembaca Layar: Uji aplikasi Anda dengan pembaca layar untuk memastikan bahwa aplikasi tersebut dapat diakses oleh pengguna dengan gangguan penglihatan. Pembaca layar populer termasuk NVDA, JAWS, dan VoiceOver.

Menerapkan Aksesibilitas di App Router Next.js

  1. Gunakan Komponen Link Next.js: Gunakan komponen `<Link>` untuk navigasi. Ini menyediakan fitur aksesibilitas bawaan, seperti prefetching dan manajemen fokus.
  2. Manajemen Fokus: Saat menavigasi antar halaman atau membuka modal, pastikan fokus dikelola dengan benar. Fokus harus diatur ke elemen yang paling logis di halaman atau modal baru.
  3. Komponen Kustom yang Dapat Diakses: Saat membuat komponen kustom, pastikan komponen tersebut dapat diakses dengan mengikuti prinsip-prinsip yang diuraikan di atas. Gunakan HTML semantik, atribut ARIA, dan navigasi keyboard untuk membuat komponen Anda dapat digunakan oleh semua orang.
  4. Linting dan Pengujian: Gunakan alat linting seperti ESLint dengan plugin aksesibilitas untuk mengidentifikasi potensi masalah aksesibilitas dalam kode Anda. Juga, gunakan alat pengujian otomatis untuk menguji aplikasi Anda terhadap pelanggaran aksesibilitas.

Kesimpulan

Sistem perutean berbasis file dari App Router Next.js menawarkan cara yang kuat dan intuitif untuk menyusun dan menavigasi aplikasi Anda. Dengan memahami konsep inti dan praktik terbaik yang diuraikan dalam panduan ini, Anda dapat membangun aplikasi Next.js yang tangguh, skalabel, dan mudah dipelihara. Bereksperimenlah dengan berbagai fitur App Router dan temukan bagaimana hal itu dapat menyederhanakan alur kerja pengembangan Anda dan meningkatkan pengalaman pengguna.