<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>, ви можете викликати <код>bind метод, щоб надати йому додаткові аргументи. Це прив'яже новий аргумент (<code>productId) ) до функції на додачу до <code>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> рендериться Серверним компонентом, а Серверна дія передається до <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 для прогресивного покращення вимагає:

  1. <form> рендериться серверним компонентом
  2. функція, передана до <form> пропу action, має бути Server Action
  3. хук 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": {}
}