Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Проверка формы и ошибки

Пользователь может отправить пустую форму. Проверка (валидация) выполняется в action на сервере: если данные не подходят, действие не сохраняет статью, а возвращает список ошибок. Компонент получает этот ответ в пропсе actionData и показывает ошибки рядом с полями.

Возврат ошибок

Дополните action в app/routes/new-post.tsx:

// app/routes/new-post.tsx
import { Form, data, redirect } from "react-router";
import type { Route } from "./+types/new-post";
import { createPost } from "../data.server";
 
export async function action({ request }: Route.ActionArgs) {
  const formData = await request.formData();
  const title = String(formData.get("title") ?? "").trim();
  const body = String(formData.get("body") ?? "").trim();
 
  const errors: { title?: string; body?: string } = {};
  if (title.length < 3) errors.title = "Заголовок — минимум 3 символа";
  if (body === "") errors.body = "Напишите текст статьи";
 
  if (Object.keys(errors).length > 0) {
    return data({ errors }, { status: 400 });
  }
 
  const post = await createPost(title, body);
  return redirect(`/posts/${post.id}`);
}

Функция data из react-router возвращает объект вместе с HTTP-статусом: 400 означает «неверный запрос». Без статуса можно вернуть и просто { errors }.

Вывод ошибок

// app/routes/new-post.tsx
export default function NewPost({ actionData }: Route.ComponentProps) {
  const errors = actionData?.errors;
 
  return (
    <Form method="post">
      <input name="title" placeholder="Заголовок" />
      {errors?.title && <p className="error">{errors.title}</p>}
 
      <textarea name="body" placeholder="Текст статьи" />
      {errors?.body && <p className="error">{errors.body}</p>}
 
      <button type="submit">Опубликовать</button>
    </Form>
  );
}

Отправьте пустую форму — под полями появятся «Заголовок — минимум 3 символа» и «Напишите текст статьи». Пока форма ни разу не отправлялась, actionData равно undefined, поэтому обращение идёт через ?..

useActionData

Пропс actionData есть только у компонента маршрута. Если форма разбита на отдельные компоненты, вложенный компонент получит тот же объект хуком:

// app/components/FieldError.tsx
import { useActionData } from "react-router";
 
export function TitleError() {
  const actionData = useActionData<{ errors?: { title?: string } }>();
  return actionData?.errors?.title ? <p>{actionData.errors.title}</p> : null;
}

Проверка в браузере

Атрибуты required и minLength дают быструю подсказку ещё до отправки. Но проверку на сервере они не заменяют: запрос можно отправить в обход формы.

Частая ошибка

После ошибки проверки поля формы оказываются пустыми, и пользователь вводит всё заново. Так бывает, если форма сбрасывается или поля управляются состоянием, которое очищается. При отправке через Form с неуправляемыми полями введённый текст остаётся на месте; если поля всё же сбрасываются, верните значения из action вместе с ошибками, например data({ errors, values: { title, body } }, { status: 400 }), и подставьте их в defaultValue.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.