Halo! Di pembahasan kita kali ini, saya akan membahas kenapa saya memilih menggunakan hook form ketimbang harus ngetik state satu satu
Dan salah satu contoh hook form yang biasa digunakan adalah react-hook-form, maka kita akan “membuka kap mesin” React Hook Form untuk benar-benar memahami keajaibannya dan kenapa kamu harus memilih nya.
Meskipun pada praktiknya nanti ada banyak hooks form lain yang bisa kamu gunakan, tapi setidaknya dengan ini kamu bisa paham dasarnya.w
Masalah: “Form Melelahkan” dengan useState
Mari kita coba buat form login sederhana hanya dengan useState, tanpa library tambahan.
// components/LoginFormWithState.jsx
"use client";
import { useState } from 'react';
export default function LoginFormWithState() {
// SATU state untuk setiap input
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
// State untuk menyimpan pesan error
const [errors, setErrors] = useState({});
const handleSubmit = (event) => {
event.preventDefault(); // Mencegah reload halaman
console.log("Mencoba submit...");
// === Validasi Manual yang Merepotkan ===
const newErrors = {};
if (!email) {
newErrors.email = "Email tidak boleh kosong.";
} else if (!/\S+@\S+\.\S+/.test(email)) {
newErrors.email = "Format email tidak valid.";
}
if (!password) {
newErrors.password = "Password tidak boleh kosong.";
} else if (password.length < 8) {
newErrors.password = "Password minimal 8 karakter.";
}
setErrors(newErrors);
// HANYA jika tidak ada error, kita lanjutkan
if (Object.keys(newErrors).length === 0) {
console.log("Data valid, siap dikirim:", { email, password });
alert("Login Berhasil! (Simulasi)");
}
};
// Perhatikan: Setiap ketikan akan me-render ulang seluruh komponen!
console.log("KOMPONEN DI-RENDER ULANG!");
return (
<form onSubmit={handleSubmit}>
<div>
<label>Email</label>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)} // Handler manual
/>
{errors.email && <p style={{ color: 'red' }}>{errors.email}</p>}
</div>
<div>
<label>Password</label>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)} // Handler manual
/>
{errors.password && <p style={{ color: 'red' }}>{errors.password}</p>}
</div>
<button type="submit">Login</button>
</form>
);
}
Masalah yang terlihat:
Banyak useState: Satu state untuk setiap input. Bayangkan jika form punya 20 input!
Banyak Re-render: Buka console log dan coba ketik. Setiap ketukan keyboard akan memicu re-render. Ini boros performa.
Kode Validasi Manual: Kita harus menulis logika validasi sendiri yang bisa menjadi sangat rumit.
Handler Manual: Kita harus menulis onChange untuk setiap input.
Ini tidak efisien. Di sinilah React Hook Form datang sebagai solusi.
React Hook Form: Sang Asisten Cerdas
1. Detail Fungsi & Filosofi
React Hook Form adalah library untuk mengelola state, validasi, dan submission form di React.
Fungsi Utamanya:
Manajemen State: Mengurus nilai dari semua input form secara internal.
Validasi: Memudahkan integrasi aturan validasi.
Error Handling: Menyediakan cara mudah untuk mengakses dan menampilkan pesan error.
Performance: Mengurangi jumlah re-render secara drastis.
Filosofinya yang Paling Penting: "Uncontrolled Components"
Cara useState (Controlled): React “mengontrol” penuh nilai input setiap saat. Setiap perubahan dikirim ke state React, lalu React mengirimnya kembali ke input. Ini seperti seorang manajer mikro yang selalu ingin tahu setiap detail kecil.
Cara React Hook Form (Uncontrolled): RHF membiarkan DOM (form itu sendiri) “mengurus dirinya sendiri”. RHF hanya akan “bertanya” nilai input saat benar-benar dibutuhkan (misalnya, saat validasi atau submit). Ini seperti manajer yang percaya pada timnya dan hanya memeriksa hasil akhirnya. Hasilnya? Performa yang jauh lebih cepat.
2. Perbandingan: Form yang Sama dengan React Hook Form
Mari kita bangun ulang form di atas dengan RHF.
"use client";
import { useForm } from 'react-hook-form';
export default function LoginFormWithRHF() {
const {
register,
handleSubmit,
formState: { errors }
} = useForm();
const onSubmit = (data) => {
// Fungsi ini HANYA akan berjalan jika validasi lolos
console.log("Data valid, siap dikirim:", data);
alert("Login Berhasil! (Simulasi)");
};
// Perhatikan: Komponen ini tidak akan re-render saat kamu mengetik!
console.log("KOMPONEN DI-RENDER ULANG!");
return (
// handleSubmit akan menangani event.preventDefault() secara otomatis
<form onSubmit={handleSubmit(onSubmit)}>
<div>
<label>Email</label>
<input
type="email"
{...register("email", {
required: "Email tidak boleh kosong.",
pattern: {
value: /\S+@\S+\.\S+/,
message: "Format email tidak valid."
}
})}
/>
{errors.email && <p style={{ color: 'red' }}>{errors.email.message}</p>}
</div>
<div>
<label>Password</label>
<input
type="password"
{...register("password", {
required: "Password tidak boleh kosong.",
minLength: {
value: 8,
message: "Password minimal 8 karakter."
}
})}
/>
{errors.password && <p style={{ color: 'red' }}>{errors.password.message}</p>}
</div>
<button type="submit">Login</button>
</form>
);
}
Lihat perbedaannya?
Tidak ada useState untuk input.
Tidak ada handler onChange manual.
Logika validasi menyatu dengan pendaftaran input, lebih bersih dan deklaratif.
Komponen tidak re-render saat mengetik!
Step-by-Step Menggunakan React Hook Form
Langkah 3: Me-register sebuah Field
“Me-register” berarti memberitahu RHF, “Hei, awasi input ini!”.
Panggil useForm: Dapatkan fungsi register dari hook useForm().
Gunakan di Input: Pada elemen <input>, gunakan spread operator ... dengan fungsi register.
<input {...register("namaFieldUnik")} />
Apa yang Dilakukan ...register?
Ini adalah “jalan pintas” cerdas yang secara otomatis memberikan props penting ke input, yaitu:name="namaFieldUnik"
onChange={...} (handler internal RHF)
onBlur={...} (handler internal RHF)
ref={...} (referensi langsung ke elemen DOM)
Langkah 4: Menambahkan Validasi (Tanpa Library Tambahan)
RHF punya sistem validasi bawaan. Kita bisa menambahkannya sebagai argumen kedua di fungsi register.
Sediakan Objek Opsi: register("fieldName", { /* opsi validasi di sini */ })
Gunakan Aturan yang Tersedia:
required: Bisa berupa true atau string pesan error.
{...register("email", { required: "Email wajib diisi!" })}
minLength & maxLength: Untuk panjang karakter. Harus berupa objek.
{...register("password", { minLength: { value: 8, message: "Minimal 8 karakter" } })}
pattern: Untuk validasi menggunakan Regular Expression (RegEx).
{...register("email", { pattern: { value: /\S+@\S+\.\S+/, message: "Format email salah" } })}
Langkah 5: Handling Error
RHF secara otomatis mengumpulkan semua error validasi ke dalam satu objek.
Dapatkan errors: Ambil errors dari formState yang disediakan useForm.
const { formState: { errors } } = useForm();
Tampilkan Pesan Error: Di bawah setiap input, periksa apakah ada error untuk field tersebut, lalu tampilkan pesannya.
{errors.email && ( <p>{errors.email.message}</p> )}
Objek errors akan memiliki key yang sama dengan nama yang kamu daftarkan (misal: errors.email, errors.password).
Langkah 6: Handling Submit
Ini adalah bagian yang paling elegan dari RHF.
Dapatkan handleSubmit: Ambil fungsi handleSubmit dari useForm().
Buat Fungsi onSubmit: Buat fungsi async atau biasa yang akan menerima data form yang sudah bersih dan tervalidasi.
const onSubmit = (data) => { // Lakukan sesuatu dengan data, misal kirim ke API console.log(data); // data akan berisi { email: '...', password: '...' } };
Bungkus di form: Gunakan handleSubmit untuk membungkus fungsi onSubmit-mu di tag <form>.
<form onSubmit={handleSubmit(onSubmit)}> {/* ... inputs ... */} </form>
Cara Kerja handleSubmit:
Ia bertindak seperti “gerbang keamanan”. Saat tombol submit diklik, handleSubmit akan:
Menjalankan semua aturan validasi yang telah kamu definisikan.
Jika ada satu saja error, ia akan berhenti dan mengisi objek errors. Fungsi onSubmit-mu tidak akan pernah dipanggil.
Jika semua validasi lolos, barulah ia akan memanggil fungsi onSubmit-mu dan memberikan data form sebagai argumen.
Kesimpulan
React Hook Form bukan sekadar library, tapi sebuah perubahan cara berpikir dalam menangani form di React. Dengan mengadopsi filosofi uncontrolled components dan menyediakan API yang kuat (register, handleSubmit), ia memungkinkan kita untuk membangun form yang:
Lebih Cepat: Karena re-render minimal.
Lebih Bersih: Karena logika terisolasi dan deklaratif.
Lebih Mudah Dikelola: Karena tidak ada state dan handler manual yang bertebaran.
Sekarang kamu sudah paham “kenapa” kita menggunakan React Hook Form. Selanjutnya, kita akan membuatnya lebih hebat lagi dengan mengintegrasikannya dengan Zod untuk validasi yang lebih kuat dan type-safe