<form>
Komponen <form>
bawaan peramban memungkinkan Anda membuat kontrol interaktif untuk mengirimkan informasi.
<form action={search}>
<input name="query" />
<button type="submit">Cari</button>
</form>
- Referensi
- Penggunaan
- Menangani pengiriman formulir di klien
- Menangani pengiriman formulir dengan Server Action
- Menampilkan status tertunda selama pengiriman formulir
- Memperbarui data formulir secara optimis
- Menangani kesalahan pengiriman formulir
- Menampilkan kesalahan pengiriman formulir tanpa JavaScript
- Menangani beberapa jenis pengiriman
Referensi
<form>
Untuk membuat kontrol interaktif untuk mengirimkan informasi, render komponen <form>
bawaan peramban.
<form action={search}>
<input name="query" />
<button type="submit">Cari</button>
</form>
Lihat contoh lainnya di bawah.
Props
<form>
mendukung semua props elemen umum.
action
: URL atau fungsi. Ketika URL diberikan ke action
, formulir akan berperilaku seperti komponen formulir HTML. Ketika fungsi diberikan ke action
, fungsi tersebut akan menangani pengiriman formulir. Fungsi yang diberikan ke action
dapat berupa async dan akan dipanggil dengan satu argumen yang berisi data formulir dari formulir yang dikirimkan. Prop action
dapat ditimpa oleh atribut formAction
pada komponen <button>
, <input type="submit">
, atau <input type="image">
.
Catatan Penting
- Ketika sebuah fungsi diberikan ke
action
atauformAction
, metode HTTP akan menjadi POST terlepas dari nilai propmethod
.
Penggunaan
Menangani pengiriman formulir di klien
Lepaskan sebuah fungsi ke prop action
dari formulir untuk menjalankan fungsi tersebut saat formulir disubmit. formData
akan diteruskan ke fungsi sebagai argumen sehingga Anda dapat mengakses data yang dikirimkan oleh formulir. Ini berbeda dari konvensional HTML action, yang hanya menerima URL.
export default function Search() { function search(formData) { const query = formData.get("query"); alert(`Anda mencari '${query}'`); } return ( <form action={search}> <input name="query" /> <button type="submit">Cari</button> </form> ); }
Menangani pengiriman formulir dengan Server Action
Render sebuah <form>
dengan input dan tombol kirim. Lepaskan Server Action (sebuah fungsi yang ditandai dengan 'use server'
) ke prop action
dari formulir untuk menjalankan fungsi tersebut saat formulir disubmit.
Melewatkan Server Action ke <form action>
memungkinkan pengguna untuk mengirimkan formulir tanpa JavaScript yang diaktifkan atau sebelum kode dimuat. Ini menguntungkan bagi pengguna yang memiliki koneksi lambat, perangkat, atau yang memiliki JavaScript dinonaktifkan dan mirip dengan cara kerja formulir ketika URL diberikan ke prop action
.
Anda dapat menggunakan field formulir tersembunyi untuk memberikan data ke aksi <form>
’s. Server Action akan dipanggil dengan data field formulir tersembunyi sebagai instance dari FormData
.
import { updateCart } from './lib.js';
function AddToCart({productId}) {
async function addToCart(formData) {
'use server'
const productId = formData.get('productId')
await updateCart(productId)
}
return (
<form action={addToCart}>
<input type="hidden" name="productId" value={productId} />
<button type="submit">Tambahkan ke Keranjang</button>
</form>
);
}
Sebagai pengganti menggunakan field formulir tersembunyi untuk memberikan data ke aksi <form>
, Anda dapat memanggil metode bind
untuk menyuplai argumen tambahan. Ini akan mengikat argumen baru (productId
) ke fungsi selain dari formData
yang diteruskan sebagai argumen ke fungsi.
import { updateCart } from './lib.js';
function AddToCart({productId}) {
async function addToCart(productId, formData) {
"use server";
await updateCart(productId)
}
const addProductToCart = addToCart.bind(null, productId);
return (
<form action={addProductToCart}>
<button type="submit">Tambahkan ke Keranjang</button>
</form>
);
}
Ketika <form>
dirender oleh Server Component, dan Server Action diteruskan ke prop action
<form>
, formulir akan ditingkatkan secara progresif.
Menampilkan status tertunda selama pengiriman formulir
Untuk menampilkan status tertunda ketika formulir sedang dikirim, Anda dapat memanggil Hook useFormStatus
dalam komponen yang dirender dalam <form>
dan membaca properti pending
yang dikembalikan.
Di sini, kami menggunakan properti pending
untuk menunjukkan formulir sedang dikirim.
import { useFormStatus } from "react-dom"; import { submitForm } from "./actions.js"; function Submit() { const { pending } = useFormStatus(); return ( <button type="submit" disabled={pending}> {pending ? "Mengirim..." : "Kirim"} </button> ); } function Form({ action }) { return ( <form action={action}> <Submit /> </form> ); } export default function App() { return <Form action={submitForm} />; }
Untuk mempelajari lebih lanjut tentang Hook useFormStatus
lihat dokumentasi referensi.
Memperbarui data formulir secara optimis
Hook useOptimistic
menyediakan cara untuk memperbarui antarmuka pengguna secara optimis sebelum operasi latar belakang, seperti permintaan jaringan, selesai. Dalam konteks formulir, teknik ini membantu membuat aplikasi terasa lebih responsif. Ketika seorang pengguna mengirimkan formulir, alih-alih menunggu respons server untuk mencerminkan perubahan, antarmuka segera diperbarui dengan hasil yang diharapkan.
Sebagai contoh, ketika seorang pengguna mengetik pesan ke dalam formulir dan menekan tombol “Kirim”, Hook useOptimistic
memungkinkan pesan tersebut segera muncul dalam daftar dengan label “Mengirim…”, bahkan sebelum pesan tersebut benar-benar dikirim ke server. Pendekatan “optimis” ini memberikan kesan kecepatan dan responsivitas. Formulir kemudian berusaha untuk benar-benar mengirim pesan di latar belakang. Setelah server mengonfirmasi pesan telah diterima, label “Mengirim…” dihapus.
import { useOptimistic, useState, useRef } from "react"; import { deliverMessage } from "./actions.js"; function Thread({ messages, sendMessage }) { const formRef = useRef(); async function formAction(formData) { addOptimisticMessage(formData.get("message")); formRef.current.reset(); await sendMessage(formData); } const [optimisticMessages, addOptimisticMessage] = useOptimistic( messages, (state, newMessage) => [ ...state, { text: newMessage, sending: true } ] ); return ( <> {optimisticMessages.map((message, index) => ( <div key={index}> {message.text} {!!message.sending && <small> (Mengirim...)</small>} </div> ))} <form action={formAction} ref={formRef}> <input type="text" name="message" placeholder="Halo!" /> <button type="submit">Kirim</button> </form> </> ); } export default function App() { const [messages, setMessages] = useState([ { text: "Halo!", sending: false, key: 1 } ]); async function sendMessage(formData) { const sentMessage = await deliverMessage(formData.get("message")); setMessages([...messages, { text: sentMessage }]); } return <Thread messages={messages} sendMessage={sendMessage} />; }
Menangani kesalahan pengiriman formulir
Dalam beberapa kasus fungsi yang dipanggil oleh prop action
dari <form>
melemparkan sebuah kesalahan. Anda dapat menangani kesalahan ini dengan membungkus <form>
dalam Error Boundary. Jika fungsi yang dipanggil oleh prop action
dari <form>
melemparkan sebuah kesalahan, fallback untuk error boundary akan ditampilkan.
import { ErrorBoundary } from "react-error-boundary"; export default function Search() { function search() { throw new Error("kesalahan pencarian"); } return ( <ErrorBoundary fallback={<p>Terjadi kesalahan saat mengirimkan formulir</p>} > <form action={search}> <input name="query" /> <button type="submit">Cari</button> </form> </ErrorBoundary> ); }
Menampilkan kesalahan pengiriman formulir tanpa JavaScript
Menampilkan pesan kesalahan pengiriman formulir sebelum bundel JavaScript dimuat untuk peningkatan progresif mengharuskan bahwa:
<form>
dirender oleh Server Component- fungsi yang diteruskan ke prop
action
<form>
adalah Server Action - Hook
useActionState
digunakan untuk menampilkan pesan kesalahan
useActionState
mengambil dua parameter: sebuah Server Action dan sebuah state awal. useActionState
mengembalikan dua nilai, sebuah variabel state dan sebuah aksi. Aksi yang dikembalikan oleh useActionState
harus diteruskan ke prop action
dari formulir. Variabel state yang dikembalikan oleh useActionState
dapat digunakan untuk menampilkan pesan kesalahan. Nilai yang dikembalikan oleh Server Action yang diteruskan ke useActionState
akan digunakan untuk memperbarui variabel state.
import { useActionState } from "react"; import { signUpNewUser } from "./api"; export default function Page() { async function signup(prevState, formData) { "use server"; const email = formData.get("email"); try { await signUpNewUser(email); alert(`Menambahkan "${email}"`); } catch (err) { return err.toString(); } } const [message, signupAction] = useActionState(signup, null); return ( <> <h1>Daftar untuk newsletter saya</h1> <p>Daftar dengan email yang sama dua kali untuk melihat kesalahan</p> <form action={signupAction} id="signup-form"> <label htmlFor="email">Email: </label> <input name="email" id="email" placeholder="react@example.com" /> <button>Daftar</button> {!!message && <p>{message}</p>} </form> </> ); }
Pelajari lebih lanjut tentang memperbarui state dari aksi formulir dengan dokumen useActionState
.
Menangani beberapa jenis pengiriman
Formulir dapat dirancang untuk menangani beberapa aksi pengiriman berdasarkan tombol yang ditekan oleh pengguna. Setiap tombol di dalam formulir dapat dikaitkan dengan aksi atau perilaku yang berbeda dengan mengatur prop formAction
.
Ketika seorang pengguna mengetuk tombol tertentu, formulir disubmit, dan aksi yang sesuai, yang ditentukan oleh atribut dan aksi tombol tersebut, dieksekusi. Misalnya, sebuah formulir mungkin mengirimkan artikel untuk ditinjau secara default tetapi memiliki tombol terpisah dengan formAction
diatur untuk menyimpan artikel sebagai draf.
export default function Search() { function publish(formData) { const content = formData.get("content"); const button = formData.get("button"); alert(`'${content}' telah dipublikasikan dengan tombol '${button}'`); } function save(formData) { const content = formData.get("content"); alert(`Draf '${content}' Anda telah disimpan!`); } return ( <form action={publish}> <textarea name="content" rows={4} cols={40} /> <br /> <button type="submit" name="button" value="submit">Publikasikan</button> <button formAction={save}>Simpan draf</button> </form> ); }