<form>
Встроенный браузерный компонент <form> позволяет создавать интерактивные элементы управления для отправки данных.
<form action={search}>
<input name="query" />
<button type="submit">Search</button>
</form>
- Справочник
-
Использование
- Обработка отправки формы на клиенте
- Обработка отправки формы с помощью серверной функции
- Отображение состояния ожидания во время отправки формы
- Оптимистичное обновление данных формы
- Обработка ошибок при отправке формы
- Отображение ошибки отправки формы без JavaScript
- Обработка нескольких типов отправки
Справочник
<form>
Чтобы создать интерактивные элементы управления для отправки данных, отрисуйте встроенный браузерный компонент <form>.
<form action={search}>
<input name="query" />
<button type="submit">Search</button>
</form> Другие примеры приведены ниже.
Свойства
<form> поддерживает все общие свойства элементов.
action: URL или функция. Если action передан URL, форма будет работать как HTML-компонент формы. Если action передана функция, она будет обрабатывать отправку формы в Transition согласно шаблону свойства Action. Функция, переданная в action, может быть асинхронной; она будет вызвана с одним аргументом, содержащим данные формы, отправленной пользователем. Свойство action можно переопределить атрибутом formAction в компоненте <button>, <input type="submit"> или <input type="image">.
Особенности
- Если в
actionилиformActionпередана функция, HTTP-методом будет POST независимо от значения свойстваmethod.
Использование
Обработка отправки формы на клиенте
Передайте функцию в свойство action элемента form, чтобы вызвать ее при отправке формы. formData будет передан функции в качестве аргумента, чтобы вы могли получить доступ к данным, отправленным формой. Это отличается от обычного HTML action, который принимает только URL-адреса. После успешного выполнения функции action все неуправляемые элементы полей формы сбрасываются.
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> ); }
Обработка отправки формы с помощью серверной функции
Отрисуйте <form> с полем ввода и кнопкой отправки. Передайте серверную функцию (функцию, помеченную директивой 'use server') в свойство action элемента form, чтобы вызвать эту функцию при отправке формы.
Передача серверной функции в <form action> позволяет пользователям отправлять формы без включенного JavaScript или до загрузки кода. Это полезно для пользователей с медленным подключением или устройством, а также для тех, у кого отключен JavaScript. Такой подход похож на работу форм, когда свойству action передан URL-адрес.
Чтобы передать данные действию <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> можно вызвать метод bind, чтобы передать ему дополнительные аргументы. Это привяжет к функции новый аргумент (productId) в дополнение к formData, передаваемому функции в качестве аргумента.
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> отрисовывается в серверном компоненте, а серверная функция передается в свойство action элемента <form>, форма прогрессивно улучшается.
Отображение состояния ожидания во время отправки формы
Чтобы отобразить состояние ожидания во время отправки формы, вызовите хук 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} />; }
Подробнее о хуке 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) => [...messages, { text: sentMessage }]); } return <Thread messages={messages} sendMessage={sendMessage} />; }
Обработка ошибок при отправке формы
В некоторых случаях функция, вызываемая свойством action компонента <form>, выбрасывает ошибку. Обработать такие ошибки можно, обернув <form> в границу ошибок (Error Boundary). Если функция, вызываемая свойством 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> ); }
Отображение ошибки отправки формы без JavaScript
Чтобы отображать сообщение об ошибке отправки формы до загрузки пакета JavaScript в рамках прогрессивного улучшения, необходимо выполнить следующие условия:
-
<form>должен отрисовываться клиентским компонентом - функция, переданная в свойство
actionкомпонента<form>, должна быть серверной функцией - для отображения сообщения об ошибке необходимо использовать хук
useActionState
useActionState принимает два параметра: серверную функцию и начальное состояние. useActionState возвращает два значения: переменную состояния и действие. Возвращенное useActionState действие следует передать в свойство action формы. Возвращенную useActionState переменную состояния можно использовать для отображения сообщения об ошибке. Значение, возвращаемое серверной функцией, переданной в useActionState, будет использовано для обновления переменной состояния.
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(`Added "${email}"`); } catch (err) { return err.toString(); } } const [message, signupAction] = useActionState(signup, null); return ( <> <h1>Signup for my newsletter</h1> <p>Signup with the same email twice to see an error</p> <form action={signupAction} id="signup-form"> <label htmlFor="email">Email: </label> <input name="email" id="email" placeholder="react@example.com" /> <button>Sign up</button> {!!message && <p>{message}</p>} </form> </> ); }
Подробнее об обновлении состояния с помощью действия формы см. в документации useActionState.
Обработка нескольких типов отправки
Формы можно настроить для выполнения разных действий отправки в зависимости от нажатой пользователем кнопки. Каждой кнопке внутри формы можно назначить отдельное действие или поведение, задав свойство 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> ); }
© 2013–present Facebook Inc.
Licensed under the Creative Commons Attribution 4.0 International Public License.
https://react.dev/reference/react-dom/components/form