Pisahkan komponennya. Server Component di App Router tidak bisa memegang onClick, onChange, atau onSubmit karena kodenya jalan di server. Buat satu file kecil berlabel use client untuk tombol atau form, lalu import file itu ke dalam page Server Component.
Penyebab onClick Error di Server Component
Page.tsx tanpa use client otomatis jadi Server Component. Komponen jenis ini hanya merender HTML di server, tidak memasang listener browser.
- Menulis onClick langsung di page.tsx memicu error build karena fungsi tidak bisa diserialisasi ke client.
- Menulis useState atau useEffect di Server Component memicu error React hook karena hook hanya jalan di client.
- Mengakses window atau document saat render server memicu error karena objek browser belum ada.
Polanya sederhana. Fetch data dan render awal tetap di server. Klik, input, dan state pindah ke Client Component.
Tabel Troubleshooting Event Handler Next Js
| Masalah | Penyebab | Solusi |
|---|---|---|
| Event handlers cannot be passed to Client Component | Fungsi inline dari Server Component dikirim sebagai props | Pindahkan handler ke file use client |
| Functions cannot be passed directly | Props berisi closure atau fungsi non-serializable | Kirim string, number, atau objek plain saja |
| useState is not allowed in Server Component | State ditulis di file server | Pindahkan state ke Client Component kecil |
// Salah: page.tsx Server Component
export default function Page() {
return <button onClick={() => alert("klik")}>Beli</button>;
}
// Benar: page.tsx tetap server
import TombolBeli from "./Tombol";
export default function Page() {
return <TombolBeli productId="p-123" />;
}
Pindahkan Interaksi ke Client Component Kecil
- Buat file Tombol.tsx sejajar page.tsx, tulis use client di baris pertama.
- Terima props serializable seperti productId atau label, hindari mengirim fungsi dari server.
- Tulis onClick, useState, atau fetch client di dalam Tombol.tsx saja.
- Import Tombol.tsx dari Server Component, biarkan page tetap fetch data produk.
"use client";
export default function Tombol({ productId }: { productId: string }) {
function handleKlik() {
console.log("beli:", productId);
}
return <button onClick={handleKlik}>Beli Sekarang</button>;
}
Jangan ubah seluruh page jadi use client kalau hanya satu tombol yang butuh interaksi. Batas client sekecil mungkin menjaga fetch server tetap cepat.
FAQ
Apakah semua onClick harus pakai use client?
Ya. Setiap elemen yang butuh onClick, onChange, atau onSubmit wajib berada di Client Component.
Bagaimana kirim data dari Server Component ke tombol?
Kirim lewat props serializable seperti string atau number, contohnya productId hasil fetch server.
Kapan pakai Server Action bukan onClick?
Pakai Server Action untuk tulis database, validasi, atau operasi sensitif yang harus jalan di server.