Проверка формы и ошибки
Пользователь может отправить пустую форму. Проверка (валидация) выполняется в 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.