Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Як показати в React-формі помилки валідації, які повернув Laravel з кодом 422?

Коли API на Laravel не пропускає дані, він відповідає 422 Unprocessable Content з JSON:

{
  "message": "The email has already been taken. (and 1 more error)",
  "errors": {
    "email": ["Ця адреса вже зайнята."],
    "items.0.qty": ["Кількість має бути не менше 1."]
  }
}

Laravel повертає JSON (а не редирект назад), якщо запит має заголовок Accept: application/json - його обов'язково треба надсилати з fetch.

З React Hook Form - setError:

const { register, handleSubmit, setError, formState: { errors } } = useForm();

async function onSubmit(values) {
  const response = await fetch('/api/orders', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
    body: JSON.stringify(values),
  });

  if (response.status === 422) {
    const { errors: serverErrors } = await response.json();
    for (const [field, messages] of Object.entries(serverErrors)) {
      setError(field, { type: 'server', message: messages[0] }, { shouldFocus: true });
    }
    return;
  }

  if (!response.ok) {
    setError('root.server', { message: 'Не вдалося зберегти. Спробуйте ще раз.' });
    return;
  }
}
{errors.root?.server && <p role="alert">{errors.root.server.message}</p>}

Що тут важливо:

  • ключі Laravel з крапками (items.0.qty) збігаються з іменами полів React Hook Form для масивів (register('items.0.qty')) - помилка потрапить точно до потрібного поля;
  • кілька повідомлень на поле - Laravel повертає масив; зазвичай показують перше;
  • помилки, що не стосуються поля (сервер недоступний, 403, 500) - окремо, через root.*;
  • серверні помилки скидаються при наступній зміні поля чи відправці - так поводиться React Hook Form для setError.

Без бібліотеки - те саме зі станом: const [errors, setErrors] = useState({}) і useActionState, що повертає errors з 422-відповіді.

Inertia поводиться інакше: там Laravel відповідає не 422, а редиректом назад з помилками в сесії, і вони приходять у сторінку як проп errors (useForm().errors) - ручна обробка не потрібна.

Інші статуси, які варто обробити: 419 (сесія чи CSRF-токен застаріли - запропонувати оновити сторінку) і 429 (забагато спроб).

Докладніше в документації: React Hook Form: setError

Схожі питання