Ngoding Next.js App Router? Wajib tahu nih kesalahan yang sering kita lupa!
Pasti kita semua setuju kalau ngoding pake Next.js App Router itu rasanya kayak naik rollercoaster. Seru, ngebut, tapi kadang bikin jantungan karena ada aja hal baru yang muncul atau bahkan hal lama yang kita kira udah paham ternyata beda banget. Jujur deh, siapa yang belum pernah kena 'jebakan betmen' gara gara lupa detail kecil pas lagi asik asiknya ngoding di App Router? Kita di Javapixa Creative Studio juga sering ngalamin kok. Makanya, kali ini kita mau bahas tuntas nih beberapa kesalahan umum yang sering banget kita lupa atau bahkan belum tahu pas lagi develop pakai App Router. Tujuannya biar kita semua bisa ngoding makin lancar jaya dan terhindar dari error error aneh yang bikin kita bengong di depan layar. Yuk, kita kupas satu per satu!
Kenalan Dulu Sama App Router Si Paling Beda
Sebelum masuk ke daftar kesalahannya, mari kita refresh sedikit kenapa App Router ini terasa begitu berbeda. Kalau kita udah terbiasa dengan Pages Router, App Router ini membawa paradigma baru yang berpusat pada React Server Components (RSC). Ini bukan cuma sekadar update fitur, tapi revolusi cara kita membangun aplikasi Next.js. Sekarang, defaultnya semua komponen itu Server Component, kecuali kita bilang lain. Konsepnya adalah memaksimalkan kerja di sisi server untuk performa yang lebih baik, bundle size yang lebih kecil, dan pengalaman developer yang lebih mulus. Tapi, di sinilah letak 'tantangan' dan potensi kesalahan yang sering kita lakukan.
Apa Itu App Router Sebenarnya App Router memperkenalkan struktur file based routing yang lebih powerful dan fleksibel. Dia menggabungkan routing dengan data fetching dan state management secara lebih terintegrasi. Dengan App Router, kita bisa bikin nested layouts, shared layouts, error boundaries, loading UIs, dan juga route groups dengan cara yang lebih elegan dan terstruktur. Ini memungkinkan kita membangun aplikasi yang sangat kompleks dengan modularitas yang tinggi. Jadi, ini bukan cuma tentang 'router' biasa, tapi ekosistem pengembangan yang komprehensif.
Beda Jauh Sama Pages Router Perbedaan paling fundamental antara App Router dan Pages Router itu ada di model renderingnya. Di Pages Router, secara default semua komponen itu Client Side Rendered (CSR), dan kita harus eksplisit pakai getServerSideProps atau getStaticProps buat fetching data di sisi server. Nah, kalau di App Router, defaultnya semua komponen itu Server Component. Artinya, kode komponen kita dieksekusi di sisi server, dan hanya hasil HTML statis atau sebagian kecil JavaScript interaktif yang dikirim ke browser. Ini mengubah total cara kita berpikir soal data fetching, interaktivitas, dan bahkan struktur proyek. Kita wajib banget paham perbedaan ini biar nggak salah langkah.
Kesalahan #1 Lupa Bedain Server Component dan Client Component
Ini dia biang kerok nomor satu yang paling sering bikin kita nyasar. Karena defaultnya semua di App Router itu Server Component, kita kadang lupa kapan harus pakai Client Component. Padahal, penggunaan yang salah bisa berdampak serius ke performa dan fungsionalitas aplikasi kita.
Ngerti Dulu Dasarnya Server Component (SC) itu ibarat tukang masak di dapur. Dia yang nyiapin semua bahan, motong motong, masak, sampai jadi hidangan utama (HTML). Dia bisa langsung akses database atau API keys tanpa khawatir terekspos ke browser. SC nggak punya state, nggak punya efek, dan nggak bisa pakai hook React seperti useState atau useEffect. Intinya, SC itu buat logika UI yang statis dan fetching data. Client Component (CC) itu kayak pelayan yang interaktif di meja makan. Dia yang ngurusin kalau ada tombol diklik, input diisi, atau animasi yang bergerak. CC butuh JavaScript di browser, bisa pakai state dan effect, tapi nggak boleh akses resource sensitif kayak database atau API keys langsung.
Kapan Sih Kita Perlu Pakai use client Keyword sakti "use client" itu harus kita taruh di paling atas file komponen kita kalau kita memang butuh interaktivitas. Misalnya, kalau komponen kita pakai useState, useEffect, useContext, atau event listener kayak onClick, nah itu wajib jadi Client Component. Atau kalau kita butuh pakai library pihak ketiga yang memang cuma jalan di browser, kayak beberapa library grafik atau animasi. Kuncinya, pakai "use client" hanya kalau benar benar diperlukan. Jangan sampai semua komponen kita dikasih "use client" gara gara takut, itu sama aja kayak balik lagi ke Pages Router dengan bundle size yang membengkak.
Dampak Kalau Salah Pakai Kalau kita pakai Server Component buat hal yang harusnya Client Component (misalnya naruh useState di SC), ya udah jelas bakal error. Sebaliknya, kalau kita bikin terlalu banyak Client Component padahal nggak perlu, kita bakal kehilangan keuntungan performa dari Server Component. Bundle size JavaScript kita akan jadi besar, waktu load awal jadi lebih lama, dan pengalaman pengguna pun kurang optimal. Ingat, tujuan App Router salah satunya adalah mengurangi JavaScript yang harus diunduh dan dieksekusi oleh browser.
Kesalahan #2 Bingung Soal Data Fetching di App Router
Dulu di Pages Router kita akrab banget sama getServerSideProps atau getStaticProps. Sekarang di App Router, ceritanya beda lagi. Kebingungan soal gimana dan di mana harus fetching data itu sering banget terjadi.
fetch di Server Component Itu Cached By Default Ini poin penting banget. Ketika kita pakai fetch() di Server Component, hasilnya itu secara default akan di cache oleh Next.js. Artinya, kalau ada request yang sama, Next.js akan langsung ngasih data dari cache tanpa perlu re fetch ke backend lagi. Ini asik banget buat performa, tapi bisa jadi masalah kalau kita butuh data yang selalu up to date. Sering kita lupa kalau ada cache ini dan bertanya tanya kenapa datanya kok nggak berubah.
Mengatur Revalidasi dengan Opsi fetch Buat ngakalin masalah caching default di fetch(), kita bisa tambahin opsi cache atau next.revalidate di parameter fetch. Misalnya: fetch('https://api.example.com/data', { cache: 'no store' }) untuk menonaktifkan cache. fetch('https://api.example.com/data', { next: { revalidate: 60 } }) untuk revalidasi setiap 60 detik. Memahami dan menggunakan opsi ini secara bijak itu kunci banget buat memastikan data kita selalu segar tanpa mengorbankan performa terlalu banyak.
Data Fetching di Client Component Meskipun App Router fokus di Server Component, kadang kita memang butuh fetching data di Client Component. Misalnya, data yang tergantung interaksi user atau data yang butuh update real time. Untuk kasus ini, kita bisa pakai library kayak SWR, React Query, atau bahkan useEffect bawaan React. Tapi ingat, kalau bisa di Server Component, usahakan di sana. Jangan sampai data yang statis atau jarang berubah malah di fetch di sisi klien yang membebani browser.
Kesalahan #3 Overuse use client
Seperti yang sempat kita singgung, terlalu banyak pakai "use client" itu ibarat kembali ke masa lalu. Maksudnya baik, biar semua jalan, tapi kita jadi kehilangan banyak keuntungan App Router.
Kapan Kita Benar Benar Butuh Kita harus pakai "use client" hanya jika komponen kita:
- Menggunakan hooks seperti
useState,useEffect,useRef,useMemo,useCallback, dll. - Menggunakan event listener seperti
onClick,onChange,onSubmit. - Mengakses DOM API secara langsung.
- Menggunakan context API (Client Context Provider).
- Menggunakan library pihak ketiga yang memang membutuhkan client side JavaScript.
Selain dari itu, usahakan tetap menjadi Server Component.
Dampak Performa yang Signifikan Setiap file dengan "use client" akan dimasukkan ke dalam JavaScript bundle yang dikirim ke browser. Semakin banyak "use client", semakin besar bundle JS kita. Ini berarti waktu download yang lebih lama, parsing JavaScript yang lebih lama, dan akhirnya First Contentful Paint (FCP) yang lebih lambat. Jadi, kita harus selektif dan memilah dengan cermat.
Strategi untuk Meminimalkan Client Side Code Ada trik asik buat ini, namanya "Pass props children". Kita bisa membungkus Client Component di dalam Server Component dan melewati prop children ke dalamnya. Dengan begitu, Server Component bisa merender bagian statis, dan hanya bagian interaktif yang di Client Component. Contoh:
jsx
// components/ClientWrapper.tsx
'use client';
import { useState } from 'react';
export default function ClientWrapper({ children }) {
const [count, setCount] = useState(0);
return (
Count: {count}
setCount(count + 1)}>Increment
{children}
);
}// app/page.tsx
import ClientWrapper from '../components/ClientWrapper';
export default function Page() {
return (
Halo dari Server Component
Ini teks statis yang dirender di server
);
}Dengan strategi ini, bagian
dan
tetap Server Component, hanya ClientWrapper dan logikanya yang di sisi klien. Hemat bundle JS kan?
Kesalahan #4 Salah Paham Soal Caching dan Revalidasi
Caching adalah pedang bermata dua. Kalau kita paham, bisa bikin aplikasi super cepat. Kalau nggak, bisa bikin data basi dan error aneh. Di App Router, caching jauh lebih kompleks dari Pages Router.
Static Rendering Itu Defaultnya Secara default, route di App Router itu di render secara statis. Artinya, saat build time, halaman itu akan di render jadi HTML statis dan bisa langsung disajikan tanpa perlu proses render di server lagi untuk setiap request. Ini bagus banget buat performa, tapi kalau datanya harus selalu dinamis, kita harus kasih tahu Next.js.
Incremental Static Regeneration (ISR) di App Router Konsep ISR tetap ada, tapi cara kerjanya beda. Kita bisa atur revalidasi di level fetch (seperti yang sudah dibahas) atau di level route dengan export const revalidate = 60; di layout.tsx atau page.tsx kita. Angka 60 di sini berarti halaman atau data akan di revalidasi setiap 60 detik. Kalau ada request masuk setelah 60 detik, Next.js akan menyajikan versi cache lama sambil di background dia akan fetching data baru untuk request berikutnya.
On Demand Revalidation Kadang kita butuh revalidasi secara instan, misalnya setelah user submit form atau update data. Untuk ini, kita bisa pakai revalidatePath atau revalidateTag dari next/cache di Server Actions atau Route Handlers. Ini penting banget biar user selalu lihat data yang paling baru setelah mereka berinteraksi dengan aplikasi. Sering kita lupa pakai ini, makanya data di halaman user kok nggak berubah ubah padahal sudah di submit.
Kesalahan #5 Nggak Optimalin Server Actions
Server Actions ini fitur baru yang powerful banget di Next.js 14 (atau 13.4 ke atas). Kita bisa langsung panggil fungsi server dari Client Component tanpa perlu bikin API endpoint terpisah. Tapi seringnya kita belum optimal memanfaatkannya.
Keunggulan Server Actions Dengan Server Actions, kita bisa dengan mudah melakukan mutasi data, memvalidasi form, dan berinteraksi dengan database langsung dari sisi klien tanpa harus membuat REST API terpisah. Ini mengurangi boilerplate code dan menyederhanakan arsitektur aplikasi kita. Lebih aman juga karena kode eksekusi di server.
Cara Pakai dan Keamanannya Server Actions itu cuma perlu kita tandai dengan "use server" di paling atas file fungsinya atau langsung di dalam fungsi itu sendiri. Contoh:
jsx
// app/actions.ts
'use server';
import { revalidatePath } from 'next/cache';Fungsi createPost ini bisa kita panggil langsung dari Client Component atau Server Component. Otomatis, Next.js akan menangani proses network request dan pengiriman data dengan aman.
Revalidasi Setelah Server Action Ini sering banget lupa. Setelah kita melakukan mutasi data pakai Server Action, kita perlu kasih tahu Next.js untuk revalidasi cache terkait. Kita bisa pakai revalidatePath atau revalidateTag di dalam Server Action itu sendiri. Tanpa ini, user mungkin nggak akan lihat perubahan data mereka sampai cache di Next.js kadaluarsa atau mereka refresh halaman secara manual. Pastikan langkah revalidasi ini selalu ada setelah operasi write data.
Kesalahan #6 Metadata Bikin Pusing Tujuh Keliling
Metadata itu penting banget buat SEO dan social sharing. Di App Router, cara ngaturnya beda banget dan kadang bikin kita bingung.
Static Metadata di layout.tsx atau page.tsx Kita bisa atur metadata statis langsung di layout.tsx atau page.tsx dengan mengekspor objek metadata. Contoh:
jsx
// app/page.tsx
export const metadata = {
title: 'Next.js App Router Tips',
description: 'Kesalahan umum App Router yang sering lupa',
};
export default function Page() { // ... }Ini asik buat metadata yang nggak berubah.
Dynamic Metadata dengan generateMetadata Function Kalau metadata kita butuh data dinamis (misalnya title halaman blog yang diambil dari database), kita bisa pakai fungsi generateMetadata yang diekspor dari layout.tsx atau page.tsx.
jsx
// app/blog/[slug]/page.tsx
import { getPostBySlug } from '@/lib/api';generateMetadata ini dijalankan di sisi server, jadi kita bisa fetching data di dalamnya.
Order of Precedence Metadata Kita juga harus paham urutan prioritas metadata. Metadata di level layout.tsx akan di override oleh metadata di page.tsx di level yang lebih dalam. Ini penting biar kita nggak bingung kenapa metadata kita kok nggak sesuai. Perhatikan struktur folder dan di mana kita mendefinisikan metadata atau generateMetadata.
Kesalahan #7 Kurang Perhatian ke Struktur Folder dan File Konvensi
App Router punya konvensi nama file dan folder yang spesifik banget. Melanggar atau nggak paham konvensi ini bisa bikin aplikasi kita nggak jalan atau bikin pusing nyari errornya.
File Konvensi Penting
layout.tsx: Untuk shared UI antar route. Ini bisa nested.page.tsx: Entry point utama untuk setiap route, wajib ada.loading.tsx: Untuk loading UI yang otomatis muncul saat data sedang di fetch.error.tsx: Untuk error boundary yang otomatis menangani error di segmen route.not-found.tsx: Untuk menampilkan halaman 404 ketika route tidak ditemukan.route.ts: Untuk membuat API endpoint atau route handler (penggantiapifolder di Pages Router).
Private Folders dengan Garis Bawah Kita bisa pakai _ (garis bawah) di awal nama folder untuk menandai folder private. Folder ini tidak akan dianggap sebagai bagian dari path URL, tapi isinya bisa diimpor dan digunakan di dalam folder lain. Ini asik buat ngumpulin komponen atau utilitas yang cuma relevan untuk segmen route tertentu.
Route Groups dengan Kurung Biasa (auth) atau (dashboard) adalah contoh route groups. Ini juga bukan bagian dari URL. Route groups memungkinkan kita mengelompokkan route yang memiliki layout.tsx terpisah tanpa memengaruhi URL. Berguna banget untuk mengatur layout yang kompleks, misalnya punya layout berbeda untuk area publik dan area dashboard admin. Sering kita lupa nih fitur ini padahal bisa bikin struktur proyek jadi rapi banget.
Colocation of Components Di App Router, kita disarankan untuk menempatkan komponen atau file terkait lainnya (misalnya utilitas, styles) di folder yang sama dengan page.tsx atau layout.tsx yang menggunakannya. Ini bikin proyek lebih modular dan mudah di maintain. Nggak perlu lagi punya satu folder components raksasa yang isinya ribuan file.
Kesalahan #8 Lupa Testing di Lingkungan Produksi
Ngoding itu asik, tapi seringnya kita cuma fokus di development environment. Padahal, App Router punya beberapa perilaku unik di production build yang bisa bikin kita kaget.
Perbedaan Dev vs Prod Build Di development, Next.js akan melakukan banyak optimasi dan menyediakan banyak feedback error yang detail. Tapi di production, banyak proses di belakang layar yang berbeda. Cache di Next.js production itu lebih agresif, console.log biasanya nggak muncul di browser (hanya di server log), dan ada beberapa fitur yang hanya aktif di production (misalnya image optimization yang pakai CDN).
Cache Differences Seperti yang sudah kita bahas, caching di App Router itu powerful. Di development, cache ini sering di reset atau kurang agresif. Tapi di production, cache ini akan bekerja sesuai konfigurasinya, dan kalau kita salah set revalidasi atau lupa, bisa jadi user kita melihat data yang basi. Jadi, pastikan selalu cek perilaku caching di lingkungan production.
Deployment Specific Issues Ketika kita deploy Next.js App Router ke platform seperti Vercel, Netlify, atau self hosted, ada potensi masalah konfigurasi yang berbeda. Misalnya, environment variables yang belum diset, atau konfigurasi serverless function yang nggak pas. Pastikan kita punya pipeline testing yang solid dan selalu lakukan smoke test di production setelah deploy. Jangan cuma andalkan npm run dev ya.
Penutup Ngoding Next js App Router Itu Seru Kok
Kita semua pernah bikin kesalahan, kok. Apalagi di dunia teknologi yang perubahannya cepat banget kayak Next.js App Router ini. Konsep Server Components dan berbagai optimasi lainnya memang butuh waktu untuk dicerna dan dipraktikkan. Tapi justru di situlah letak keseruannya. Kita jadi belajar hal baru, berpikir dengan cara yang berbeda, dan membangun aplikasi yang jauh lebih performa.
Semoga daftar kesalahan yang sering kita lupa ini bisa jadi pengingat asik buat kita semua. Ingat, kuncinya adalah terus belajar, banyakin eksplorasi, dan jangan takut mencoba hal baru. Dengan pemahaman yang tepat tentang App Router, kita bisa bikin aplikasi web yang nggak cuma fungsional, tapi juga super cepat dan memberikan pengalaman pengguna yang luar biasa. Selamat ngoding, teman teman!