<form>
Розширення React для <form>
наразі доступні лише в Canary та експериментальному каналах React. У стабільних релізах React <form>
працює лише як вбудований HTML-компонент браузера . Дізнайтеся більше про канали релізів React тут.
Вбудований компонент браузера <form>
дозволяє створювати інтерактивні елементи керування для подання інформації.
<form action={search}>
<input name="query" />
<button type="submit">Search</button>
</form>
Довідник
<form>
Щоб створити інтерактивні елементи керування для надсилання інформації, відрендеріть вбудований у браузер <form>
компонент.
<form action={search}>
<input name="query" />
<button type="submit">Search</button>
</form>
Дивіться більше прикладів нижче.
Пропси
<form>
підтримує всі пропси спільних елементів.
action
: URL або функція. Якщо до action
передано URL-адресу, форма поводитиметься як компонент HTML-форми. Якщо до action
передано функцію, вона буде обробляти надсилання форми. Функція, передана до action
, може бути асинхронною і буде викликана з єдиним аргументом, що містить дані форми надісланої форми. Проп action
може бути перевизначений атрибутом formAction
як <button>
, <input type="submit">
або <input type="image">
компонент.
Застереження
- Коли функція передається до
action
абоformAction
метод HTTP буде POST незалежно від значення пропуmethod
.
Використання
Обробити відправлення форми на клієнтськйі стороні
Передайте функцію в проп action
форми, щоб запустити функцію при відправленні форми. formData
буде передано функції як аргумент, щоб ви могли отримати доступ до даних, надісланих формою. Це відрізняється від звичайної HTML-дії, яка приймає тільки URL-адреси.
export default function Search() {
function search(formData) {
const query = formData.get("query");
alert(`You searched for '${query}'`);
}
return (
<form action={search}>
<input name="query" />
<button type="submit">Search</button>
</form>
);
}
{
"dependencies": {
"react": "18.3.0-canary-6db7f4209-20231021",
"react-dom": "18.3.0-canary-6db7f4209-20231021",
"react-scripts": "^5.0.0"
},
"main": "/index.js",
"devDependencies": {}
}
Обробка надсилання форми за допомогою дії сервера
Відрендерити <form>
з кнопкою введення і відправки. Передайте серверну дію (функцію, позначену 'use server'
) у проп action
форми, щоб запустити функцію, коли форму буде надіслано.
Передача дії сервера до <form action>
дозволяє користувачам надсилати форми без увімкненого JavaScript або до завантаження коду. Це корисно для користувачів з повільним з'єднанням, пристроєм або з вимкненим JavaScript і схоже на те, як працюють форми, коли URL передається в проп action
.
Ви можете використовувати приховані поля форми для надання даних до дії <form>
. Серверна дія буде викликана з даними прихованого поля форми як екземпляр 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">Add to Cart</button>
</form>
);
}
Замість використання прихованих полів форми для надання даних до дії <form>
, ви можете викликати
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">Add to Cart</button>
</form>
);
}
Коли <form>
рендериться Серверним компонентом, а Серверна дія передається до <form>
пропсу action
, форма має вигляд прогресивно покращена.
Показувати стан очікування під час надсилання форми
Щоб відобразити стан очікування під час надсилання форми, ви можете викликати хук useFormStatus
у компоненті, відрендереному у <form>
, і прочитати повернуту властивість pending
.
Тут ми використовуємо властивість pending
, щоб вказати, що форма надсилається.
import { useFormStatus } from "react-dom";
import { submitForm } from "./actions.js";
function Submit() {
const { pending } = useFormStatus();
return (
<button type="submit" disabled={pending}>
{pending ? "Submitting..." : "Submit"}
</button>
);
}
function Form({ action }) {
return (
<form action={action}>
<Submit />
</form>
);
}
export default function App() {
return <Form action={submitForm} />;
}
export async function submitForm(query) {
await new Promise((res) => setTimeout(res, 1000));
}
{
"dependencies": {
"react": "canary",
"react-dom": "canary",
"react-scripts": "^5.0.0"
},
"main": "/index.js",
"devDependencies": {}
}
Щоб дізнатися більше про хук useFormStatus
, зверніться до довідкової документації.
Оптимістичне оновлення даних форми
Хук useOptimistic
надає спосіб оптимізованого оновлення інтерфейсу користувача до завершення фонової операції, наприклад, мережевого запиту. У контексті форм ця техніка допомагає зробити програми більш чуйними. Коли користувач надсилає форму, замість того, щоб чекати на відповідь сервера, щоб відобразити зміни, інтерфейс негайно оновлюється з очікуваним результатом.
Наприклад, коли користувач вводить повідомлення у форму і натискає кнопку "Відправити", хук useOptimistic
дозволяє повідомленню негайно з'явитися у списку з міткою "Відправлення...", ще до того, як повідомлення буде відправлено на сервер. Такий "оптимістичний" підхід створює враження швидкості та оперативності. Потім форма намагається дійсно відправити повідомлення у фоновому режимі. Як тільки сервер підтвердить, що повідомлення отримано, мітку "Відправлення..." буде видалено.
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> (Sending...)</small>}
</div>
))}
<form action={formAction} ref={formRef}>
<input type="text" name="message" placeholder="Hello!" />
<button type="submit">Send</button>
</form>
</>
);
}
export default function App() {
const [messages, setMessages] = useState([
{ text: "Hello there!", 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} />;
}
export async function deliverMessage(message) {
await new Promise((res) => setTimeout(res, 1000));
return message;
}
{
"dependencies": {
"react": "18.3.0-canary-6db7f4209-20231021",
"react-dom": "18.3.0-canary-6db7f4209-20231021",
"react-scripts": "^5.0.0"
},
"main": "/index.js",
"devDependencies": {}
}
Обробка помилок надсилання форми
У деяких випадках функція, викликана пропсом <form>
action
, викликає помилку. Ви можете обробити ці помилки, обгорнувши <form>
у межу помилки. Якщо функція, викликана пропсом <form>
action
<form>
, спричиняє помилку, буде показано запасний варіант для межі помилки.
import { ErrorBoundary } from "react-error-boundary";
export default function Search() {
function search() {
throw new Error("search error");
}
return (
<ErrorBoundary
fallback={<p>There was an error while submitting the form</p>}
>
<form action={search}>
<input name="query" />
<button type="submit">Search</button>
</form>
</ErrorBoundary>
);
}
{
"dependencies": {
"react": "18.3.0-canary-6db7f4209-20231021",
"react-dom": "18.3.0-canary-6db7f4209-20231021",
"react-scripts": "^5.0.0",
"react-error-boundary": "4.0.3"
},
"main": "/index.js",
"devDependencies": {}
}
Відображати помилку надсилання форми без JavaScript
Відображення повідомлення про помилку надсилання форми перед завантаженням пакета JavaScript для прогресивного покращення вимагає:
<form>
рендериться серверним компонентом- функція, передана до
<form>
пропуaction
, має бути Server Action - хук
useFormState
буде використано для відображення повідомлення про помилку
useFormState
приймає два параметри: Дію сервера та початковий стан. useFormState
повертає два значення, змінну стану та дію. Дію, яку повертає useFormState
, слід передати у проп форми action
. Змінна стану, яку повертає useFormState
, може бути використана для виведення повідомлення про помилку. Значення, повернуте дією сервера, передане useFormState
, буде використано для оновлення змінної стану.
import { useFormState } from "react-dom";
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(`Added "${email}"`);
} catch (err) {
return err.toString();
}
}
const [message, formAction] = useFormState(signup, null);
return (
<>
<h1>Signup for my newsletter</h1>
<p>Signup with the same email twice to see an error</p>
<form action={formAction} id="signup-form">
<label htmlFor="email">Email: </label>
<input name="email" id="email" placeholder="[email protected]" />
<button>Sign up</button>
{!!message && <p>{message}</p>}
</form>
</>
);
}
let emails = [];
export async function signUpNewUser(newEmail) {
if (emails.includes(newEmail)) {
throw new Error("This email address has already been added");
}
emails.push(newEmail);
}
{
"dependencies": {
"react": "18.3.0-canary-6db7f4209-20231021",
"react-dom": "18.3.0-canary-6db7f4209-20231021",
"react-scripts": "^5.0.0"
},
"main": "/index.js",
"devDependencies": {}
}
Дізнайтеся більше про оновлення стану з дії форми з документації useFormState
Обробка декількох типів надсилання
.Форми можуть бути розроблені для обробки декількох дій надсилання на основі натиснутої користувачем кнопки. Кожна кнопка у формі може бути пов'язана з окремою дією або поведінкою за допомогою параметра пропу formAction
.
Коли користувач натискає певну кнопку, форма надсилається і виконується відповідна дія, визначена атрибутами та дією цієї кнопки. Наприклад, за замовчуванням форма може надсилати статтю на рецензування, але мати окрему кнопку з formAction
, призначену для збереження статті як чернетки.
export default function Search() {
function publish(formData) {
const content = formData.get("content");
const button = formData.get("button");
alert(`'${content}' was published with the '${button}' button`);
}
function save(formData) {
const content = formData.get("content");
alert(`Your draft of '${content}' has been saved!`);
}
return (
<form action={publish}>
<textarea name="content" rows={4} cols={40} />
<br />
<button type="submit" name="button" value="submit">Publish</button>
<button formAction={save}>Save draft</button>
</form>
);
}
{
"dependencies": {
"react": "18.3.0-canary-6db7f4209-20231021",
"react-dom": "18.3.0-canary-6db7f4209-20231021",
"react-scripts": "^5.0.0"
},
"main": "/index.js",
"devDependencies": {}
}