Tutorial Next JS 14 Pemula: App Router vs Pages Router

Routing merupakan salah satu komponen penting dalam setiap projek website. Dengan routing yang baik, pengguna dapat mengakses halaman-halaman di dalam website dengan lebih mudah, memberikan pengalaman yang nyaman dan responsif.

Routing yang tertata dengan baik juga membantu developer dalam mengelola navigasi antar halaman, sehingga setiap bagian dari website bisa diakses secara efisien. Pentingnya routing membuat developer harus memilih dan menerapkan metode routing yang sesuai dengan kebutuhan projek web development mereka.

Next.js hadir sebagai salah satu framework JavaScript modern yang sangat populer dan mendukung konsep file-based routing. Ini berarti setiap file yang diletakkan di dalam folder tertentu secara otomatis menjadi rute yang bisa diakses pada URL. Dalam Next.js 14, ada dua konsep utama terkait routing yang perlu dipahami, yaitu App Router dan Pages Router.

Kedua konsep ini memiliki tujuan yang sama, yaitu mengelola navigasi halaman, namun dengan cara kerja yang berbeda. Pada artikel ini, kita akan membahas secara singkat mengenai perbedaan kedua jenis router tersebut untuk membantu pemula memahami bagaimana mereka bekerja di dalam Next.js 14.

Apa Itu App Router di Next.js?

App Router di Next.js adalah pendekatan modern untuk pengelolaan routing yang diperkenalkan mulai dari Next.js 13 dan semakin dikembangkan di versi Next.js 14. Tidak seperti Pages Router yang menggunakan folder pages, App Router bekerja dengan folder app, di mana setiap file di dalamnya secara otomatis menjadi rute di aplikasi. Konsep ini menawarkan pendekatan yang lebih fleksibel dan modular dalam pengelolaan rute, serta mendukung fitur-fitur canggih seperti React Server Components dan nested routing.

Berikut contoh bagaimana cara membuat beberapa rute dengan App Router:

// app/page.tsx
import React from 'react';

const HomePage = () => {
  return (
    <div>
      <h1>Selamat Datang di Home Page</h1>
      <p>Ini adalah halaman utama menggunakan App Router di Next.js 14.</p>
    </div>
  );
}

export default HomePage;

Pada contoh di atas, file page.tsx yang berada di folder app secara otomatis menjadi halaman utama yang diakses melalui rute /. Ini menunjukkan betapa mudahnya membuat rute di App Router tanpa perlu konfigurasi yang rumit.

Jika Anda ingin membuat halaman lain seperti halaman "Tentang", cukup tambahkan file baru:

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

const AboutPage = () => {
  return (
    <div>
      <h1>Halaman Tentang</h1>
      <p>Ini adalah halaman tentang menggunakan App Router di Next.js 14.</p>
    </div>
  );
}

export default AboutPage;

Dengan struktur ini, halaman About akan dapat diakses melalui /about tanpa tambahan konfigurasi apa pun. Anda juga bisa membuat subrute dengan struktur file yang lebih dalam. Misalnya, untuk halaman produk dengan subrute:

// app/products/[id]/page.tsx
import React from 'react';

const ProductDetail = ({ params }: { params: { id: string } }) => {
  return (
    <div>
      <h1>Detail Produk {params.id}</h1>
      <p>Informasi produk dengan ID {params.id}.</p>
    </div>
  );
}

export default ProductDetail;

File di atas akan menghasilkan rute dinamis untuk halaman detail produk yang dapat diakses melalui /products/[id], di mana [id] adalah parameter dinamis. Misalnya, jika Anda ingin melihat produk dengan ID 123, Anda dapat mengakses /products/123.

Beberapa keuntungan lain menggunakan App Router di Next.js 14 adalah:

  • Modular dan Terorganisir: Struktur rute lebih rapi dengan memisahkan file berdasarkan fungsinya. Contohnya, logika untuk data fetching dapat dipisah ke dalam komponen server, sedangkan UI klien tetap di komponen klien.
  • Optimisasi Performa: Dengan React Server Components, bagian tertentu dari halaman bisa dirender di server dan dikirim ke klien, mengurangi waktu loading di browser.
  • Nested Routes: Mendukung pembuatan rute bertingkat (nested routes), yang sangat membantu ketika membuat struktur halaman yang kompleks seperti aplikasi e-commerce dengan halaman produk, ulasan, dan kategori.

Dengan semua fitur yang ditawarkan, App Router cocok digunakan dalam proyek yang membutuhkan pengelolaan rute yang lebih kompleks dan performa tinggi.

Perbandingan App Router vs Pages Router di Next.js 14

KriteriaApp RouterPages Router
FlexibilitySangat fleksibel, mendukung React Server Components dan nested routing. Misalnya, jika Anda memiliki halaman produk dengan subhalaman untuk ulasan dan detail produk, App Router memungkinkan Anda membuat struktur seperti /product/[id]/reviews dan /product/[id]/details dengan mudah.Fleksibilitas lebih terbatas, namun tetap mendukung kebutuhan routing sederhana seperti /about atau /contact. Misalnya, aplikasi portofolio atau landing page dapat dikelola dengan mudah menggunakan Pages Router.
Folder StructureMenggunakan folder app, setiap file atau folder di dalamnya otomatis menjadi rute. Sebagai contoh, app/blog/page.tsx akan menjadi /blog di URL. Folder terstruktur dengan baik, memungkinkan pemisahan logika server dan klien secara terorganisir.Menggunakan folder pages, di mana setiap file di dalamnya langsung menjadi rute. Misalnya, file pages/about.js akan otomatis menjadi /about. Struktur ini lebih sederhana, memudahkan developer untuk melihat secara langsung rute yang tersedia dalam aplikasi.
Use Case ScenarioCocok untuk aplikasi dengan rute kompleks, seperti aplikasi e-commerce atau sistem manajemen yang memiliki banyak halaman dinamis, termasuk integrasi SSR dan SSG untuk optimasi performa.Cocok untuk aplikasi kecil hingga menengah, seperti blog sederhana, portofolio, atau aplikasi satu halaman (SPA) yang tidak memerlukan struktur rute yang kompleks atau fitur SSR yang rumit.

Dengan App Router, Anda mendapatkan kontrol yang lebih baik dalam hal pembagian komponen server dan klien, sedangkan Pages Router lebih cocok untuk aplikasi yang membutuhkan setup cepat dengan rute yang sederhana.

Contoh Struktur Folder Lengkap: App Router vs Pages Router

Berikut adalah contoh struktur folder lengkap untuk App Router dan Pages Router di Next.js agar lebih jelas bagaimana kedua pendekatan ini diimplementasikan dalam proyek.

Struktur Folder: App Router

Pada App Router, semua file rute diletakkan di dalam folder app. Setiap file atau folder di dalamnya secara otomatis menjadi rute sesuai dengan struktur folder tersebut.

my-next-app/
├── app/
│   ├── layout.tsx          // Layout utama untuk semua halaman
│   ├── page.tsx            // Halaman utama (rute "/")
│   ├── about/
│   │   └── page.tsx        // Halaman tentang (rute "/about")
│   ├── products/
│   │   ├── page.tsx        // Halaman produk (rute "/products")
│   │   └── [id]/
│   │       └── page.tsx    // Halaman detail produk dengan ID dinamis (rute "/products/[id]")
│   ├── blog/
│   │   ├── layout.tsx      // Layout khusus untuk semua halaman blog
│   │   ├── page.tsx        // Halaman utama blog (rute "/blog")
│   │   └── [slug]/
│   │       └── page.tsx    // Halaman artikel blog dinamis (rute "/blog/[slug]")
├── public/
│   └── favicon.ico         // Ikon situs
├── styles/
│   └── globals.css         // CSS global
└── next.config.js          // Konfigurasi Next.js

Pada struktur di atas:

  • File layout.tsx digunakan untuk mendefinisikan layout yang bisa digunakan di seluruh halaman dalam app.
  • Folder dinamis menggunakan tanda kurung seperti [id] dan [slug] untuk mendukung rute dinamis.
  • Setiap halaman, seperti about/page.tsx, secara otomatis diakses melalui URL yang sesuai dengan struktur foldernya.

Struktur Folder: Pages Router

Untuk Pages Router, semua file rute diletakkan di dalam folder pages. Setiap file di dalam folder ini menjadi rute otomatis berdasarkan nama file atau folder tersebut.

my-next-app/
├── pages/
│   ├── index.js            // Halaman utama (rute "/")
│   ├── about.js            // Halaman tentang (rute "/about")
│   ├── products/
│   │   └── index.js        // Halaman produk (rute "/products")
│   ├── products/
│   │   └── [id].js         // Halaman detail produk dengan ID dinamis (rute "/products/[id]")
│   ├── blog/
│   │   ├── index.js        // Halaman utama blog (rute "/blog")
│   │   └── [slug].js       // Halaman artikel blog dinamis (rute "/blog/[slug]")
├── public/
│   └── favicon.ico         // Ikon situs
├── styles/
│   └── globals.css         // CSS global
└── next.config.js          // Konfigurasi Next.js

Pada struktur di atas:

  • File index.js di dalam pages menjadi halaman utama yang dapat diakses melalui /.
  • Rute dinamis ditangani dengan file [id].js atau [slug].js, mirip dengan App Router.
  • Tidak ada layout terpisah seperti di App Router, sehingga struktur ini lebih sederhana dan langsung.

Fitur Segments di App Router Next.js

Segments dalam App Router di Next.js adalah bagian dari URL yang dipisahkan oleh garis miring /. Setiap segmen ini dapat berupa rute statis atau dinamis. Dalam App Router, Anda dapat memanfaatkan segmen untuk membagi dan mengatur rute menjadi lebih modular dan fleksibel, termasuk dukungan untuk rute dinamis, parameter opsional, dan pengelompokan.

Berikut beberapa konsep segmen yang bisa diterapkan di App Router:

  • Static Segment: Rute statis seperti /products atau /about.
  • Dynamic Segment: Rute dengan parameter dinamis seperti /products/[id].
  • Optional Segment: Segmen opsional yang mungkin ada atau tidak dalam URL.
  • Parallel Routes: Menangani beberapa segmen yang dapat muncul secara paralel.

Contoh Penerapan Segments di App Router

Kita akan melihat contoh bagaimana segmen bekerja di App Router dengan mengimplementasikan rute untuk produk dengan ID dinamis dan kategori opsional.

Struktur Folder:

app/
├── products/
│   ├── [id]/
│   │   ├── page.tsx       // Halaman detail produk
│   │   └── [category]/
│       └── page.tsx       // Halaman produk dengan kategori opsional

Rute Dinamis (Dynamic Segment) untuk Produk Berdasarkan ID:

// app/products/[id]/page.tsx
import React from 'react';

const ProductDetail = ({ params }: { params: { id: string } }) => {
  return (
    <div>
      <h1>Detail Produk {params.id}</h1>
      <p>Informasi lengkap tentang produk dengan ID {params.id}.</p>
    </div>
  );
}

export default ProductDetail;

Pada contoh ini, segmen [id] digunakan untuk menangani rute dinamis. Ketika pengguna mengakses /products/123, halaman ini akan menampilkan informasi produk dengan ID 123. Segmen dinamis [id] memungkinkan rute ini menangani berbagai nilai ID tanpa membuat rute statis untuk setiap produk.

Segmen Opsional (Optional Segment) untuk Kategori:

// app/products/[id]/[category]/page.tsx
import React from 'react';

const ProductCategory = ({ params }: { params: { id: string; category?: string } }) => {
  return (
    <div>
      <h1>Produk {params.id}</h1>
      {params.category ? (
        <p>Kategori: {params.category}</p>
      ) : (
        <p>Produk ini tidak memiliki kategori khusus.</p>
      )}
    </div>
  );
}

export default ProductCategory;

Di sini, kita menambahkan segmen [category] di dalam rute [id] untuk menangani kategori produk yang mungkin opsional. Ketika pengguna mengakses /products/123/electronics, kategori electronics akan ditampilkan. Namun, jika hanya mengakses /products/123, maka produk akan tetap ditampilkan tanpa kategori, dan pesan default akan diberikan.

Kesimpulan

  • Static Segment digunakan untuk rute yang selalu sama, seperti /products atau /about.
  • Dynamic Segment memungkinkan Anda menangani berbagai nilai, seperti ID produk atau nama kategori, tanpa membuat rute statis untuk setiap variasi.
  • Optional Segment digunakan untuk menangani bagian URL yang mungkin ada atau tidak, sehingga Anda bisa membuat rute yang lebih fleksibel.

Dengan fitur segments di App Router, Anda dapat membangun rute yang lebih dinamis dan modular, mengurangi kompleksitas dalam menangani URL yang bervariasi dalam aplikasi Anda.

Apa Itu Dynamic Routes?

Dynamic routes adalah rute yang memungkinkan URL untuk menangani parameter dinamis. Contohnya, dalam sebuah aplikasi e-commerce, halaman detail produk mungkin perlu menangani URL seperti /products/123, di mana 123 adalah ID dari produk tersebut. Dengan dynamic routes, Anda dapat membuat satu rute yang menangani berbagai nilai dinamis, seperti ID atau slug produk, tanpa perlu membuat rute terpisah untuk setiap produk.

Dynamic routes sangat berguna ketika Anda memiliki data yang bervariasi, seperti postingan blog, produk, atau pengguna, yang diakses melalui URL dinamis.

Dynamic Routes di App Router

Dalam App Router di Next.js, dynamic routes diimplementasikan dengan membuat folder yang menggunakan tanda kurung ([ ]) di sekitar nama parameter dinamis. Misalnya, jika Anda ingin membuat rute dinamis untuk detail produk berdasarkan ID, Anda bisa membuat folder [id].

Berikut adalah contoh implementasi dynamic routes di App Router:

// app/products/[id]/page.tsx
import React from 'react';

const ProductDetail = ({ params }: { params: { id: string } }) => {
  return (
    <div>
      <h1>Detail Produk {params.id}</h1>
      <p>Ini adalah informasi produk dengan ID {params.id}.</p>
    </div>
  );
}

export default ProductDetail;

Pada contoh di atas:

  • Folder products berisi folder dinamis [id].
  • File page.tsx di dalam folder [id] akan menangani URL seperti /products/123, di mana 123 adalah nilai dinamis untuk ID produk.
  • Parameter dinamis id diakses melalui properti params, yang secara otomatis diteruskan ke komponen oleh Next.js.

Anda dapat menambahkan rute dinamis tambahan dengan struktur folder yang lebih dalam, seperti /products/[id]/reviews, menggunakan folder dinamis lainnya seperti [id] di dalam products.

Dynamic Routes di Pages Router

Dalam Pages Router, dynamic routes juga diimplementasikan dengan membuat file menggunakan tanda kurung ([ ]). Namun, daripada menggunakan folder, Anda akan membuat file dengan nama parameter dinamis di dalam folder pages.

Berikut adalah contoh implementasi dynamic routes di Pages Router:

// pages/products/[id].js
import React from 'react';
import { useRouter } from 'next/router';

const ProductDetail = () => {
  const router = useRouter();
  const { id } = router.query;

  return (
    <div>
      <h1>Detail Produk {id}</h1>
      <p>Ini adalah informasi produk dengan ID {id}.</p>
    </div>
  );
}

export default ProductDetail;

Pada contoh di atas:

  • File [id].js di dalam folder products menangani rute dinamis untuk produk berdasarkan ID, seperti /products/123.
  • Untuk mendapatkan nilai dinamis dari URL, digunakan hook useRouter dari Next.js. router.query.id memberikan akses ke parameter id dari URL.

Dynamic routes di Pages Router bekerja mirip dengan App Router, tetapi perbedaannya terletak pada struktur folder dan cara pengambilan parameter dari URL (menggunakan useRouter() di Pages Router).

Apa Itu Nested Routing?

Nested routing adalah konsep di mana satu rute dapat memiliki rute anak atau subrute yang terkait. Ini berarti bahwa di dalam satu halaman atau komponen, Anda bisa memiliki beberapa bagian atau halaman lain yang diakses sebagai subrute. Nested routing sangat bermanfaat untuk aplikasi yang memiliki struktur hierarkis atau rute yang lebih kompleks, seperti aplikasi e-commerce dengan halaman produk yang memiliki tab untuk ulasan, detail, dan spesifikasi produk.

Nested Routing di App Router

Dalam App Router di Next.js, nested routing diimplementasikan dengan menggunakan folder bertingkat di dalam folder app. Struktur folder ini mencerminkan bagaimana rute dan subrute akan muncul di URL. Setiap folder mewakili bagian dari rute, sehingga Anda bisa dengan mudah membuat rute bertingkat.

Berikut contoh implementasi nested routing di App Router:

// app/products/[id]/layout.tsx
import React from 'react';

const ProductLayout = ({ children }: { children: React.ReactNode }) => {
  return (
    <div>
      <h1>Halaman Produk</h1>
      <div>{children}</div> {/* Subrute akan di-render di sini */}
    </div>
  );
}

export default ProductLayout;

// app/products/[id]/page.tsx
import React from 'react';

const ProductDetail = ({ params }: { params: { id: string } }) => {
  return (
    <div>
      <h2>Detail Produk {params.id}</h2>
      <p>Informasi detail tentang produk dengan ID {params.id}.</p>
    </div>
  );
}

export default ProductDetail;

// app/products/[id]/reviews/page.tsx
import React from 'react';

const ProductReviews = ({ params }: { params: { id: string } }) => {
  return (
    <div>
      <h2>Ulasan Produk {params.id}</h2>
      <p>Berikut adalah ulasan untuk produk dengan ID {params.id}.</p>
    </div>
  );
}

export default ProductReviews;

Pada struktur ini:

  • Folder products/[id] memiliki file layout.tsx yang bertindak sebagai layout untuk semua halaman terkait produk. Komponen children di layout ini akan menampilkan halaman yang lebih spesifik seperti detail atau ulasan produk.
  • File page.tsx di dalam folder [id] menangani rute utama produk, misalnya /products/123.
  • Folder reviews di dalam [id] membuat rute tambahan, sehingga rute /products/123/reviews menampilkan halaman ulasan produk. Komponen ini di-render di dalam children pada ProductLayout.

Dengan nested routing, Anda bisa mengatur struktur halaman yang lebih kompleks, seperti /products/123, /products/123/reviews, atau /products/123/specifications.

Nested Routing di Pages Router

Dalam Pages Router, nested routing juga bisa diterapkan dengan struktur folder bertingkat. Meskipun Pages Router tidak memiliki konsep layout bawaan seperti App Router, Anda bisa menggunakan komponen React biasa untuk menangani layout dan navigasi antar subhalaman.

Berikut adalah contoh implementasi nested routing di Pages Router:

// pages/products/[id].js
import React from 'react';
import Link from 'next/link';

const ProductDetail = ({ id }) => {
  return (
    <div>
      <h2>Detail Produk {id}</h2>
      <p>Informasi tentang produk dengan ID {id}.</p>
      <nav>
        <Link href={`/products/${id}/reviews`}>Lihat Ulasan</Link>
      </nav>
    </div>
  );
}

export async function getServerSideProps(context) {
  const { id } = context.params;
  return {
    props: { id },
  };
}

export default ProductDetail;

// pages/products/[id]/reviews.js
import React from 'react';

const ProductReviews = ({ id }) => {
  return (
    <div>
      <h2>Ulasan Produk {id}</h2>
      <p>Berikut adalah ulasan untuk produk dengan ID {id}.</p>
    </div>
  );
}

export async function getServerSideProps(context) {
  const { id } = context.params;
  return {
    props: { id },
  };
}

export default ProductReviews;

Pada struktur ini:

  • File [id].js di dalam folder products menangani halaman detail produk pada rute /products/[id].
  • Folder products/[id] berisi file reviews.js, yang menjadi subrute untuk menampilkan ulasan produk dengan rute /products/[id]/reviews.
  • Navigasi antar subrute dilakukan melalui komponen Link di halaman utama produk.

Perbedaan utamanya adalah dalam Pages Router, layout atau tampilan halaman biasanya dibuat di dalam setiap file, sedangkan di App Router, layout bisa dipisah dengan lebih modular menggunakan file layout.tsx.

Kesimpulan

  • App Router mendukung nested routing secara lebih modular dengan layout.tsx yang memungkinkan subrute di-render dalam komponen layout yang sama, sehingga lebih cocok untuk aplikasi dengan struktur rute yang kompleks.
  • Pages Router menggunakan struktur folder yang serupa untuk nested routing, tetapi tidak memiliki fitur layout bawaan, sehingga perlu menggunakan komponen React biasa untuk mengelola tampilan antar halaman.

Latihan Menerapkan App Router pada Proyek Simple E-commerce: CRUD Products dan Transaction

Pada latihan ini, kita akan mencoba menerapkan App Router di Next.js untuk membangun proyek e-commerce sederhana dengan fitur CRUD untuk produk dan transaksi. Dengan menggunakan App Router, kita dapat memanfaatkan routing yang fleksibel dan modular, yang sangat cocok untuk aplikasi seperti e-commerce. Proyek ini akan terdiri dari dua bagian utama: manajemen produk (CRUD) dan transaksi.

Membuat CRUD Products

Untuk memulai, kita akan membuat rute untuk menampilkan daftar produk, menambahkan produk baru, mengedit produk, dan menghapus produk. Setiap rute ini akan dikelola oleh App Router di dalam folder app.

Struktur Folder:

app/
├── products/
│   ├── page.tsx          // Menampilkan daftar produk
│   ├── create/
│   │   └── page.tsx      // Menambahkan produk baru
│   └── [id]/
│       ├── page.tsx      // Menampilkan detail produk
│       └── edit/
│           └── page.tsx  // Mengedit produk

Menampilkan Daftar Produk:

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

const ProductsPage = () => {
  const products = [
    { id: 1, name: 'Produk A', price: 10000 },
    { id: 2, name: 'Produk B', price: 20000 },
  ];

  return (
    <div>
      <h1>Daftar Produk</h1>
      <ul>
        {products.map((product) => (
          <li key={product.id}>
            {product.name} - Rp {product.price}
            <a href={`/products/${product.id}`}>Detail</a>
            <a href={`/products/${product.id}/edit`}>Edit</a>
          </li>
        ))}
      </ul>
      <a href="/products/create">Tambah Produk Baru</a>
    </div>
  );
};

export default ProductsPage;

Di halaman ini, kita menampilkan daftar produk beserta tautan untuk melihat detail produk atau mengedit produk.

Menambahkan Produk Baru:

// app/products/create/page.tsx
import React, { useState } from 'react';

const CreateProductPage = () => {
  const [name, setName] = useState('');
  const [price, setPrice] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log({ name, price }); // Di sini bisa ditambahkan logika untuk menyimpan data
  };

  return (
    <div>
      <h1>Tambah Produk Baru</h1>
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          placeholder="Nama Produk"
          value={name}
          onChange={(e) => setName(e.target.value)}
        />
        <input
          type="number"
          placeholder="Harga Produk"
          value={price}
          onChange={(e) => setPrice(e.target.value)}
        />
        <button type="submit">Simpan</button>
      </form>
    </div>
  );
};

export default CreateProductPage;

Form ini memungkinkan pengguna untuk menambahkan produk baru ke dalam daftar. Anda bisa memperluas logika dengan menambahkan API untuk menyimpan data ke database.

Mengedit Produk:

// app/products/[id]/edit/page.tsx
import React, { useState } from 'react';

const EditProductPage = ({ params }: { params: { id: string } }) => {
  const [name, setName] = useState('Produk A'); // Nilai awal bisa diambil dari API
  const [price, setPrice] = useState(10000);    // Nilai awal bisa diambil dari API

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log({ id: params.id, name, price }); // Di sini bisa ditambahkan logika untuk mengupdate data
  };

  return (
    <div>
      <h1>Edit Produk {params.id}</h1>
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          value={name}
          onChange={(e) => setName(e.target.value)}
        />
        <input
          type="number"
          value={price}
          onChange={(e) => setPrice(e.target.value)}
        />
        <button type="submit">Simpan Perubahan</button>
      </form>
    </div>
  );
};

export default EditProductPage;

Halaman ini memungkinkan pengguna untuk mengedit produk berdasarkan ID produk. Anda bisa menggunakan API untuk mengambil dan mengupdate data produk.

Membuat CRUD Transactions

Selanjutnya, kita akan menambahkan rute untuk transaksi yang mengikuti pola serupa seperti manajemen produk.

Struktur Folder:

app/
├── transactions/
│   ├── page.tsx              // Menampilkan daftar transaksi
│   ├── create/
│   │   └── page.tsx          // Menambahkan transaksi baru
│   └── [id]/
│       ├── page.tsx          // Menampilkan detail transaksi
│       └── edit/
│           └── page.tsx      // Mengedit transaksi

Menampilkan Daftar Transaksi:

// app/transactions/page.tsx
import React from 'react';

const TransactionsPage = () => {
  const transactions = [
    { id: 1, product: 'Produk A', total: 2, amount: 20000 },
    { id: 2, product: 'Produk B', total: 1, amount: 20000 },
  ];

  return (
    <div>
      <h1>Daftar Transaksi</h1>
      <ul>
        {transactions.map((transaction) => (
          <li key={transaction.id}>
            {transaction.product} - {transaction.total} item - Rp {transaction.amount}
            <a href={`/transactions/${transaction.id}`}>Detail</a>
            <a href={`/transactions/${transaction.id}/edit`}>Edit</a>
          </li>
        ))}
      </ul>
      <a href="/transactions/create">Tambah Transaksi Baru</a>
    </div>
  );
};

export default TransactionsPage;

Halaman ini menampilkan daftar transaksi, dan menyediakan tautan untuk melihat detail transaksi atau mengeditnya.

Menambahkan Transaksi Baru:

// app/transactions/create/page.tsx
import React, { useState } from 'react';

const CreateTransactionPage = () => {
  const [product, setProduct] = useState('');
  const [total, setTotal] = useState('');
  const [amount, setAmount] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log({ product, total, amount }); // Di sini bisa ditambahkan logika untuk menyimpan data transaksi
  };

  return (
    <div>
      <h1>Tambah Transaksi Baru</h1>
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          placeholder="Produk"
          value={product}
          onChange={(e) => setProduct(e.target.value)}
        />
        <input
          type="number"
          placeholder="Jumlah"
          value={total}
          onChange={(e) => setTotal(e.target.value)}
        />
        <input
          type="number"
          placeholder="Total Harga"
          value={amount}
          onChange={(e) => setAmount(e.target.value)}
        />
        <button type="submit">Simpan</button>
      </form>
    </div>
  );
};

export default CreateTransactionPage;

Form ini memungkinkan pengguna untuk menambahkan transaksi baru dengan memasukkan produk, jumlah, dan harga total.

Dengan menggunakan App Router, Anda dapat mengelola rute secara modular, memisahkan setiap fitur (produk dan transaksi) menjadi halaman dan subrute yang terstruktur dengan baik.

Contoh Kesalahan Saat Mengerjakan Routing pada Proyek Next.js

Berikut adalah tiga contoh kesalahan umum yang sering terjadi ketika mengerjakan routing pada proyek Next.js, beserta contoh koding lengkapnya.

Kesalahan 1: Tidak Mengatur Rute Dinamis dengan Benar

Salah satu kesalahan umum adalah tidak menggunakan tanda kurung untuk parameter dinamis dalam rute. Misalnya, saat Anda ingin membuat rute dinamis untuk produk berdasarkan ID, tetapi Anda menggunakan nama file biasa, bukannya tanda kurung ([id]).

Kesalahan:

// app/products/id/page.tsx (Tidak menggunakan tanda kurung [id])
import React from 'react';

const ProductDetail = () => {
  return (
    <div>
      <h1>Detail Produk</h1>
      <p>Ini adalah halaman produk tanpa parameter dinamis.</p>
    </div>
  );
}

export default ProductDetail;

Pada contoh ini, file id/page.tsx tidak akan menangani parameter dinamis seperti /products/123 karena Next.js menganggap id sebagai rute statis. Untuk mengatasi masalah ini, Anda harus menggunakan tanda kurung untuk membuat rute dinamis yang benar.

Perbaikan:

// app/products/[id]/page.tsx (Menggunakan tanda kurung [id] untuk parameter dinamis)
import React from 'react';

const ProductDetail = ({ params }: { params: { id: string } }) => {
  return (
    <div>
      <h1>Detail Produk {params.id}</h1>
      <p>Informasi produk dengan ID {params.id}.</p>
    </div>
  );
}

export default ProductDetail;

Kesalahan 2: Tidak Menggunakan Link dengan Benar

Kesalahan lain yang sering terjadi adalah menggunakan tag <a> langsung tanpa menggunakan komponen <Link> dari Next.js. Ini bisa menyebabkan halaman direload sepenuhnya ketika berpindah halaman, padahal Next.js mendukung navigasi antar halaman secara client-side.

Kesalahan:

// pages/products/index.js
import React from 'react';

const ProductsPage = () => {
  return (
    <div>
      <h1>Daftar Produk</h1>
      <a href="/products/123">Lihat Detail Produk</a> {/* Ini akan menyebabkan full reload */}
    </div>
  );
}

export default ProductsPage;

Pada contoh ini, penggunaan <a href="/products/123"> akan menyebabkan halaman direload penuh, yang mengabaikan optimasi client-side routing dari Next.js.

Perbaikan:

// pages/products/index.js
import React from 'react';
import Link from 'next/link';

const ProductsPage = () => {
  return (
    <div>
      <h1>Daftar Produk</h1>
      <Link href="/products/123">
        <a>Lihat Detail Produk</a> {/* Menggunakan Link untuk client-side navigation */}
      </Link>
    </div>
  );
}

export default ProductsPage;

Dengan menggunakan <Link>, Next.js akan melakukan navigasi antar halaman tanpa reload penuh, yang jauh lebih cepat dan lebih efisien.

Kesalahan 3: Tidak Menyertakan Default Page di Nested Routes

Ketika menggunakan nested routes, kesalahan umum lainnya adalah tidak menyertakan file page.tsx atau index.js pada rute utama, sehingga menyebabkan error saat mengakses rute induk.

Kesalahan:

// app/products/[id]/reviews/page.tsx (Hanya ada subrute, tapi tidak ada rute induk)
import React from 'react';

const ReviewsPage = ({ params }: { params: { id: string } }) => {
  return (
    <div>
      <h1>Ulasan untuk Produk {params.id}</h1>
    </div>
  );
}

export default ReviewsPage;

Pada contoh ini, rute /products/123/reviews akan berfungsi dengan baik, tetapi jika Anda mencoba mengakses /products/123, Anda akan mendapatkan error karena tidak ada file page.tsx di folder [id].

Perbaikan:

// app/products/[id]/page.tsx (Menambahkan halaman default untuk rute induk)
import React from 'react';

const ProductDetail = ({ params }: { params: { id: string } }) => {
  return (
    <div>
      <h1>Detail Produk {params.id}</h1>
      <p>Informasi produk dengan ID {params.id}.</p>
    </div>
  );
}

export default ProductDetail;

Dengan menambahkan halaman default di rute induk (/products/[id]/page.tsx), Anda dapat memastikan bahwa rute /products/123 dan subrute /products/123/reviews keduanya berfungsi dengan baik.

Penutup

Membangun proyek dengan Next.js, terutama dalam hal routing, membutuhkan pemahaman yang baik agar aplikasi berjalan dengan efisien dan mudah dikelola. Dengan menghindari kesalahan umum dan memahami konsep seperti dynamic routes serta nested routing, Anda dapat mengembangkan aplikasi yang lebih terstruktur dan performa tinggi.

Bagi Anda yang ingin memperdalam ilmu web development, termasuk dalam pengembangan aplikasi dengan Next.js, Laravel, atau framework lainnya, Anda bisa belajar bersama mentor expert di Buildwithangga.

Dengan bergabung, Anda akan mendapatkan berbagai benefit menarik seperti akses selamanya ke materi pembelajaran, portofolio berkualitas yang bisa ditampilkan kepada klien atau perekrut, konsultasi langsung dengan mentor untuk mendapatkan bimbingan dan saran, serta banyak lagi manfaat lainnya yang akan membantu Anda menjadi developer yang lebih handal.

Ayo, tingkatkan skill Anda dan bangun karier yang lebih baik bersama Buildwithangga!