Menu

Hook useActionState di React: Formulir, Error, dan Pending

useActionState membungkus action async, menyimpan nilai terakhir yang dikembalikannya, dan memberi tahu apakah action itu masih berjalan. Pelajari signature-nya, form action, cara mengembalikan error validasi, dan cara memanggilnya di luar formulir.

Halaman ini dilengkapi editor yang bisa dijalankan. Edit, jalankan, dan lihat output-nya seketika.

useActionState adalah hook React 19 yang menjalankan fungsi async (sebuah action), menyimpan apa pun yang dikembalikannya sebagai state, dan memberi tahu apakah action itu masih berjalan. Kamu memanggilnya sebagai const [state, formAction, isPending] = useActionState(action, initialState) lalu memberikan formAction ke <form>.

Kirim formulir kosong dulu: action mengembalikan object error dan pesannya muncul. Lalu ketik alamat yang berisi @ dan kirim lagi. Selama satu detik, tombolnya bertuliskan "Subscribing..." dan dinonaktifkan.

Sintaksnya

const [state, formAction, isPending] = useActionState(action, initialState, permalink?);
  • action adalah fungsi yang dijalankan. React memanggilnya sebagai action(previousState, ...args). Apa pun yang dikembalikannya (atau hasil resolve-nya, kalau async) menjadi state yang baru.
  • initialState adalah state sebelum action pernah berjalan. Pakai bentuk yang sama dengan yang dikembalikan action, agar komponen juga bisa membaca state.message di render pertama.
  • state adalah hasil terbaru.
  • formAction adalah versi action-mu yang sudah dibungkus. Berikan ke <form action> atau <button formAction>, atau panggil sendiri.
  • isPending bernilai true sejak action dimulai sampai selesai.
  • permalink bersifat opsional dan hanya penting untuk Server Function di sebuah framework: URL yang harus dituju formulir kalau dikirim sebelum JavaScript selesai dimuat.

Action menerima state sebelumnya sebagai argumen pertama. Ini kesalahan paling umum saat memindahkan sebuah formulir: menulis async function save(formData) membuatmu mendapatkan state lama di formData, dan formData.get melempar error.

Membaca formulir dengan FormData

Saat formAction dipakai sebagai action sebuah formulir, React memanggil action-mu dengan FormData dari formulir itu. Setiap field yang punya name ada di dalamnya. Kamu tidak butuh useState untuk input-nya atau handler onChange, dan kamu tidak memanggil e.preventDefault(): React yang menangani event submit.

Hilangkan centang Spicy lalu kirim lagi: key spicy hilang dari data yang dicatat, karena checkbox yang tidak dicentang tidak mengirim apa pun. Action ini juga membaca previousState.count untuk menambahkan satu, itulah sebabnya state sebelumnya datang lebih dulu.

Mengembalikan error validasi

Validasi tempatnya di dalam action. Kembalikan error sebagai bagian dari state, dan kembalikan nilai yang diketik pengguna agar formulir bisa memasangnya lagi. Setelah form action selesai, React mereset field uncontrolled di formulir, jadi field tanpa defaultValue={state.values...} akan kembali kosong setelah submit yang gagal.

Ketik nama satu huruf dan password yang pendek, lalu kirim. Kedua error muncul dan kedua field tetap berisi apa yang kamu ketik. Hapus defaultValue={state.values.name} lalu kirim lagi: field nama mengosongkan dirinya setelah error.

Di aplikasi sungguhan, jadikan server sebagai penentu akhir. Pengecekan di client memberi umpan balik cepat, tapi siapa pun bisa mengirim request tanpa melewati formulirmu.

Memanggil action di luar formulir

formAction adalah fungsi, jadi tombol atau effect juga bisa memanggilnya. Saat kamu memanggilnya sendiri, bungkus pemanggilannya di startTransition. Formulir melakukannya untukmu; onClick biasa tidak, dan tanpa transition isPending tidak diperbarui dengan benar (React mencatat error tentang hal itu di development).

Klik Load more beberapa kali. Setiap pemanggilan dimulai dari state yang dikembalikan pemanggilan sebelumnya, jadi halaman-halaman ditambahkan secara berurutan. Kalau kamu memanggil action lagi selagi masih berjalan, React mengantrekan pemanggilan itu dan menjalankannya setelah yang sekarang selesai, masing-masing dengan state terbaru.

Asal-usul useActionState

Sebelum React 19 dirilis, hook ini tersedia di build canary sebagai useFormState, yang di-import dari react-dom. Namanya lalu diganti menjadi useActionState, dipindahkan ke react, dan diberi nilai isPending. Kalau kamu menemukan kode lama seperti ini, perbaikannya ada di import dan namanya:

// React canary, before 19
import { useFormState } from 'react-dom';
const [state, formAction] = useFormState(action, initialState);

// React 19
import { useActionState } from 'react';
const [state, formAction, isPending] = useActionState(action, initialState);

Untuk menampilkan state pending di tombol submit yang bersarang dalam, useFormStatus dari react-dom membaca status formulir induknya tanpa props. Ringkasan React 19 mencantumkannya bersama fitur formulir lainnya.

Error dan kapan memakai cara lain

Kalau action melempar error, React menampilkan error boundary terdekat alih-alih memperbarui state. Untuk error yang bisa diperbaiki pengguna, seperti validasi atau username yang sudah dipakai, kembalikan sebagai state, seperti di contoh pendaftaran. Biarkan kegagalan yang sungguhan melempar error.

useActionState dipakai untuk hasil dari sebuah action. Untuk nilai yang langsung diperbarui selama action berjalan, seperti jumlah like yang harus naik saat diklik, gabungkan dengan useOptimistic. Untuk input yang berubah di setiap ketukan tombol dan dibaca saat render, useState biasa dan controlled input tetap menjadi alat yang tepat.

Kesalahan umum

Lupa parameter state sebelumnya. async function save(formData) menerima state sebelumnya di formData. Untuk formulir, signature-nya selalu (previousState, formData).

Input tanpa name. FormData hanya berisi field yang punya atribut name. Field yang hanya punya id tidak ada di formData.get(...), yang mengembalikan null.

Controlled input di mana-mana. Kamu tetap bisa memakai value dan onChange di dalam form action, tapi tidak wajib. Field uncontrolled dengan name dan defaultValue lebih cocok untuk action, dan reset yang dilakukan React setelah submit hanya memengaruhi field uncontrolled.

Membaca state di dalam action. state dari komponen adalah nilai dari render yang membuat handler tersebut. Di dalam action, pakai previousState, yang selalu berisi hasil pemanggilan sebelumnya, bahkan saat beberapa pemanggilan sedang diantrekan.

Melempar error untuk kesalahan yang sudah diperkirakan. Error yang dilempar akan mengganti formulir dengan error boundary terdekat. Password yang salah bukanlah crash; kembalikan sebagai state.

Pertanyaan yang sering diajukan

Apa yang dikembalikan useActionState?

Array berisi tiga item: state saat ini (nilai terakhir yang dikembalikan action, atau state awal sebelum action pernah berjalan), action baru untuk diberikan ke formulir atau dipanggil sendiri, dan isPending, yang bernilai true selama action berjalan.

Argumen apa yang diterima action?

Pertama state sebelumnya, lalu apa pun yang dipakai untuk memanggil action. Di <form action={formAction}>, argumen kedua itu adalah FormData dari formulir.

Apa bedanya useActionState dan useFormState?

Keduanya hook yang sama. Hook ini dirilis di React canary sebagai useFormState di react-dom, lalu diganti namanya menjadi useActionState dan dipindahkan ke react untuk React 19, sekaligus mendapat nilai isPending.

Bisakah useActionState dipakai tanpa formulir?

Bisa. Panggil sendiri action yang dikembalikan, di dalam startTransition, misalnya dari onClick sebuah tombol. Tanpa transition, isPending tidak diperbarui dengan benar dan React mencatat error di development.

Mengapa formulir saya kosong lagi setelah dikirim?

Setelah form action selesai, React mereset field uncontrolled di formulir, seperti yang dilakukan browser setelah submit biasa. Untuk mempertahankan nilai setelah error, kembalikan nilai itu di state dan berikan ke defaultValue milik field.

Ilustrasi bahasa pemrograman di Coddy

Belajar coding dengan Coddy

Mulai