Next.js App Router: Kenapa `use client` Kamu Sebenarnya Nggak Perlu Sampai Sebanyak Itu
Next.js App Router itu ibarat kita dikasih mobil sport terbaru, tapi di saat yang sama, kita juga harus belajar lagi cara parkir paralel yang benar. Next.js 13 dan 14, dengan App Router-nya, membawa Server Components sebagai default. Ini adalah game changer yang sangat masif, janji performa gokil, bundle size yang super ramping, dan kecepatan loading yang bikin aplikasi kita terasa responsif banget.
Tapi, di tengah euforia performa ini, muncul satu 'kata kunci' yang sering banget disalahgunakan dan akhirnya malah jadi bumerang: use client.
Javapixa Creative Studio, dalam banyak proyek pengembangan aplikasi dan jasa website modern menggunakan Next.js, sering banget nemuin anti-pattern di mana hampir semua komponen yang interaktif—bahkan yang seharusnya statis—dikasih label use client. Jika kamu merasa file use client kamu sudah kayak rumput liar yang tumbuh di mana-mana, artikel ini tepat buat kamu. Karena pada dasarnya, kamu nggak perlu sampai sebanyak itu, bro.
Kenapa use client Jadi Masalah? Padahal Kan Gampang Tinggal Tambahin Aja
Mari kita luruskan dulu pondasinya. Konsep utama di App Router adalah Server Components (SC). SC dijalankan sepenuhnya di server, menghasilkan HTML murni, dan hasilnya dikirim ke browser tanpa JavaScript di dalamnya (kecuali untuk bagian yang perlu di-hydrate). Ini cepat, aman (bisa akses database atau API key langsung), dan zero bundle size di sisi klien.
Client Components (CC), yang ditandai dengan use client, berfungsi seperti komponen React yang kita kenal dulu. Mereka butuh JavaScript untuk di-render, mereka yang bertanggung jawab atas hydration (proses mengubah HTML statis menjadi elemen interaktif), dan mereka yang bisa menggunakan hooks (seperti useState, useEffect, useContext) serta browser APIs (seperti window atau localStorage).
Masalahnya muncul ketika developer terbiasa dengan pola lama: setiap ada sedikit interaksi, langsung saja use client di bagian atas file.
Dampak dari Client Component Sprawl (CC Sprawl):
- Hydration Overhead: Setiap CC harus di-hydrate. Semakin banyak CC, semakin banyak JS yang harus diunduh dan diproses browser. Ini malah memperlambat Time to Interactive (TTI), membatalkan janji performa Server Components.
- Besarnya Bundle Size: Meskipun komponennya kecil,
use clientmemastikan semua dependensinya juga harus diunduh oleh klien. - Hilangnya Server Power: Komponen yang sudah di-mark sebagai
use clienttidak bisa lagi menggunakan fitur server-side seperti mengambil data langsung dari database atau menggunakanasync/awaituntuk fetching data.
Tujuan kita adalah menjaga Server Components sebagai mayoritas, dan Client Components sebagai minoritas yang sangat terisolasi. Ini adalah kunci arsitektur Next.js yang robust dan performant.
*
4 Strategi Jitu Mengisolasi use client (The Next.js Pro Tips)
Untuk meminimalkan penggunaan use client tanpa mengorbankan interaktivitas, kita harus mengubah cara berpikir tentang di mana batas antara server dan klien diletakkan. Ini bukan tentang "apakah komponen ini punya interaksi?", tapi "seberapa kecil bagian yang benar-benar butuh interaksi?".
1. The Classic Move: Dorong Batasan Klien ke Level Paling Bawah ("Move Client Boundaries Down")
Ini adalah prinsip paling fundamental di App Router. Jangan pernah mendeklarasikan layout atau kontainer statis sebagai Client Component jika hanya ada satu elemen kecil di dalamnya yang interaktif.
Contoh Kasus: Halaman Produk
Misalnya, kita punya halaman detail produk. Di dalamnya ada:
- Header dan Deskripsi (Statis, bisa dari Server).
- Gambar Produk (Statis, bisa dari Server).
- Tombol "Add to Cart" yang punya state loading (Interaktif, butuh
useState).
Pola Buruk (Sprawl):
javascript
// ProductDetailPage.jsx
'use client'; // <-- SALAH BESAR
// ... seluruh logika render, termasuk deskripsi, gambar, dan tombol ...Dengan pola ini, seluruh halaman, yang 95% isinya statis, harus di-hydrate di browser.
Pola Benar (Isolation):
javascript
// ProductDetailPage.jsx (Server Component - DEFAULT)
import AddToCartButton from '@/components/AddToCartButton';
import ProductDescription from '@/components/ProductDescription'; // SCexport default async function ProductPage({ params }) {
const product = await getProductData(params.id); // Server Fetching
return (
{/ Semua ini di-render di Server /}
{/ HANYA bagian ini yang menjadi Client Component /}
);
}// AddToCartButton.jsx (Client Component)
'use client';
import { useState } from 'react';Takeaway: Komponen induk yang besar harus tetap menjadi Server Component. Hanya elemen terkecil yang memerlukan interaksi (seperti tombol, form input dengan state, atau modal trigger) yang harus diberi label use client.
2. The Server Magic: Menggunakan Props children untuk Menghemat Bundling
Next.js sangat pintar. Ia tahu bahwa meskipun sebuah Server Component memanggil sebuah Client Component, jika Server Component tersebut melewati komponen lain melalui prop children, maka children tersebut akan tetap di-render di server.
Ini adalah trik terkuat untuk memastikan layout atau konten statis tidak terpengaruh oleh hydration yang dilakukan oleh Client Component di sekitarnya.
Konsep: Kita menggunakan Client Component hanya sebagai "Shell" atau Boundary interaktivitas, tetapi kita mengisi Shell tersebut dengan konten yang sudah di-render oleh Server Component (melalui children).
Contoh Kasus: Sidebar yang collapsible
Kita ingin sidebar yang bisa dibuka/ditutup (butuh state/Client Component), tetapi konten di dalam sidebar (misalnya, daftar navigasi statis) harus di-render di server.
javascript
// CollapsibleSidebar.jsx (Client Component - HANYA untuk state buka/tutup)
'use client';
import { useState } from 'react';export default function CollapsibleSidebar({ children }) {
const [isOpen, setIsOpen] = useState(true);
return (
{/ Tombol yang butuh state /}
setIsOpen(!isOpen)}>Toggle
{/ Konten Server Component dimasukkan melalui children /}
{children}
);
}javascript
// DashboardLayout.jsx (Server Component - Default)
import CollapsibleSidebar from './CollapsibleSidebar';
import NavLinks from './NavLinks'; // NavLinks adalah Server Component statisApa yang terjadi? NavLinks sepenuhnya diproses di server, diubah menjadi HTML, dan HTML tersebut kemudian disalurkan sebagai children ke CollapsibleSidebar Client Component. Saat CollapsibleSidebar di-hydrate, ia hanya fokus pada logikanya sendiri (state isOpen), tetapi konten NavLinks sudah ada dan tidak perlu di-hydrate, menghemat bundle size secara signifikan.
3. Mengisolasi Kebutuhan Browser API (Context and Hooks)
Salah satu alasan terbesar mengapa file harus menggunakan use client adalah karena mereka membutuhkan akses ke API browser (window, document, atau context providers seperti Redux atau TanStack Query).
Daripada membuat layout.tsx atau page.tsx menjadi Client Component hanya karena kamu butuh Context Provider, isolasilah provider tersebut dalam satu file terpisah.
Pola Benar: The Provider Wrapper
Buat satu file khusus untuk semua providers yang memerlukan use client.
javascript
// app/providers.jsx (Client Component)
'use client';
import { ThemeProvider } from 'next-themes';
import { QueryClientProvider, QueryClient } from '@tanstack/react-query';const queryClient = new QueryClient();Kemudian, di app/layout.tsx (yang merupakan Server Component default), Anda cukup mengimpor dan menggunakan wrapper ini:
javascript
// app/layout.tsx (Server Component)
import Providers from './providers';Dengan cara ini, seluruh komponen yang dirender di dalam children (halaman, layout, dsb.) tetap dipertahankan sebagai Server Components, sementara kita hanya membayar harga hydration kecil untuk wrapper provider.
4. Fetching Data dan useEffect yang Tidak Perlu
Banyak developer secara otomatis menggunakan useEffect untuk fetching data di Client Component. Dalam App Router, ini hampir selalu merupakan praktik yang tidak efisien.
Hindari:
javascript
// ComponentWithData.jsx
'use client';
import { useState, useEffect } from 'react';export default function ComponentWithData() {
const [data, setData] = useState(null);Utamakan:
Gunakan Server Components untuk initial data fetching. Fungsi fetch di Server Component sudah otomatis di-cache dan didukung oleh React Server Component, jauh lebih cepat dan efisien.
javascript
// ComponentWithData.jsx (Server Component)
export default async function ComponentWithData() {
const res = await fetch('https://api.example.com/data');
const data = await res.json();
// Render data langsung
return {data.title};
}Jika kamu benar-benar butuh client-side fetching (misalnya, polling data atau fetching setelah interaksi pengguna), gunakan SWR atau TanStack Query yang sudah dikonfigurasi dengan provider (seperti pada poin 3), dan pastikan hanya komponen yang benar-benar melakukan re-fetching yang diberi label use client.
*
Standar Profesional Javapixa Creative Studio
Di Javapixa Creative Studio, efisiensi arsitektur bukan sekadar opsi—ini adalah standar kualitas. Ketika kami membangun aplikasi atau jasa website menggunakan Next.js App Router, perhatian terhadap batas Server dan Client adalah prioritas utama.
Mengapa ini penting bagi klien kami?
- Skalabilitas Jangka Panjang: Dengan arsitektur yang bersih, pengembangan fitur baru menjadi lebih mudah dan risiko bug akibat hydration mismatch berkurang drastis.
- Performa Maksimal: Kami menjamin aplikasi memiliki skor Core Web Vitals yang optimal karena kami meminimalkan JS di sisi klien, memaksimalkan kecepatan First Contentful Paint (FCP).
- Biaya Hosting Lebih Rendah: Server Components yang efisien berarti payload yang dikirim lebih kecil, menghemat biaya bandwidth dan mempercepat deployment.
Jika tim developer kamu saat ini sedang berjuang dengan performa aplikasi Next.js yang terasa berat, kemungkinan besar kamu sedang mengalami CC Sprawl. Mengubah pola pikir dari "React biasa" ke "Next.js Server Component First" memang butuh adaptasi, tetapi imbalannya berupa aplikasi yang jauh lebih cepat dan lebih mudah dirawat.
Ingat, setiap kali kamu menulis use client, tanyakan pada dirimu: "Apakah seluruh file ini benar-benar membutuhkan browser API atau state?" Jika jawabannya hanya untuk satu tombol kecil, maka sudah saatnya kamu menerapkan pola isolasi di atas. Biarkan server melakukan semua pekerjaan berat yang bisa dilakukannya. Keep the Client Components minimal, isolated, and focused.