nextjsformserver-actionsuxMenengah3 mnt baca

Form dengan Server Actions

Membangun form lengkap: pending state, pesan sukses, dan reset form setelah submit.

Form tanpa JavaScript pun jalan

Karena Server Action terikat ke atribut action bawaan HTML, form tetap berfungsi walau JavaScript dimatikan. Browser melakukan POST biasa dan Next.js menangani sisanya. Ini fondasi yang kokoh, lalu kita poles UX-nya.

Pending state

Tampilkan status loading saat form diproses dengan hook useFormStatus:

tsx
// app/kontak/tombol.tsx
"use client";

import { useFormStatus } from "react-dom";

export function TombolKirim() {
  const { pending } = useFormStatus();
  return (
    <button type="submit" disabled={pending}>
      {pending ? "Mengirim..." : "Kirim"}
    </button>
  );
}

useFormStatus harus dipakai di komponen terpisah (tidak bisa di komponen yang sama dengan <form>), karena ia membaca status form induknya.

Pesan sukses dan reset

Gabungkan useActionState untuk pesan hasil, dan reset form setelah sukses:

tsx
"use client";

import { useActionState, useRef } from "react";
import { kirimPesan } from "./actions";
import { TombolKirim } from "./tombol";

export default function FormKontak() {
  const formRef = useRef<HTMLFormElement>(null);
  const [state, action] = useActionState(async (prev: unknown, fd: FormData) => {
    const hasil = await kirimPesan(fd);
    if (hasil.sukses) formRef.current?.reset();
    return hasil;
  }, null);

  return (
    <form ref={formRef} action={action}>
      <input name="nama" placeholder="Nama" required />
      <textarea name="pesan" placeholder="Pesan" required />
      <TombolKirim />
      {state?.sukses && <p>Pesan terkirim, terima kasih!</p>}
    </form>
  );
}

Kesalahan umum pemula

  • Memakai useFormStatus di komponen yang sama dengan <form>. Hook ini membaca status form induk, jadi harus di komponen anak (misal komponen tombol terpisah).
  • Lupa revalidatePath setelah mutasi. Data tersimpan tapi halaman masih menampilkan data lama. Panggil revalidasi di dalam action.
  • Tidak men-disable tombol saat pending. User bisa double-submit dan membuat data ganda. Selalu disable tombol saat pending.

Latihan singkat

  1. Buat form tambah todo dengan tombol yang menampilkan "Menyimpan..." saat pending dan disable selama proses.
  2. Setelah todo tersimpan, reset form otomatis dan tampilkan pesan sukses yang hilang setelah 3 detik.

Rangkuman

  • useFormStatus memberi status pending; dipakai di komponen tombol terpisah.
  • useActionState mengelola hasil action dan menampilkannya di form.
  • Reset form setelah sukses dan panggil revalidatePath agar data diperbarui.
  • Selalu disable tombol saat pending untuk mencegah double-submit.

Catatan teknis: Setelah action yang mengubah data, panggil revalidatePath di dalam Server Action agar halaman yang menampilkan data tersebut diperbarui. Tanpa ini, user bisa melihat data lama walau simpannya sudah sukses.