Форма с валидацией

Собираем практичную форму регистрации с валидацией — закрепляем управляемые поля, состояние и события.

Валидация формы в React — это просто ещё одно состояние: вы храните введённые значения и объект ошибок, а при отправке проверяете данные.

Что строим

Форма с полями e-mail и пароль. Правила: e-mail должен содержать @, пароль — минимум 6 символов. Ошибки показываем под полями.

Состояние: значения и ошибки

Заведём два состояния — для значений полей и для сообщений об ошибках:

import { useState } from "react";

function SignupForm() {
  const [form, setForm] = useState({ email: "", password: "" });
  const [errors, setErrors] = useState({});

  function handleChange(e) {
    const { name, value } = e.target;
    setForm((prev) => ({ ...prev, [name]: value }));
  }
  // ... продолжение ниже
}

Функция валидации

Вынесем проверку в отдельную функцию — она возвращает объект ошибок (пустой, если всё хорошо):

function validate(form) {
  const errors = {};
  if (!form.email.includes("@")) {
    errors.email = "E-mail должен содержать @";
  }
  if (form.password.length < 6) {
    errors.password = "Минимум 6 символов";
  }
  return errors;
}

Логику проверки удобно протестировать отдельно на чистом JS:

function validate(form) {
  const errors = {};
  if (!form.email.includes("@")) errors.email = "E-mail должен содержать @";
  if (form.password.length < 6) errors.password = "Минимум 6 символов";
  return errors;
}
console.log(validate({ email: "bad", password: "123" }));
console.log(validate({ email: "[email protected]", password: "secret1" }));

Вывод:

{ email: 'E-mail должен содержать @', password: 'Минимум 6 символов' }
{}

Пустой объект {} означает «ошибок нет» — форму можно отправлять.

Отправка с проверкой

В обработчике onSubmit отменяем перезагрузку, валидируем и либо показываем ошибки, либо «отправляем»:

function handleSubmit(e) {
  e.preventDefault();
  const found = validate(form);
  setErrors(found);

  if (Object.keys(found).length === 0) {
    console.log("Регистрируем:", form);
    // здесь был бы запрос на сервер
  }
}

Разметка с выводом ошибок

Под каждым полем условно показываем ошибку через &&:

return (
  <form onSubmit={handleSubmit}>
    <input name="email" value={form.email} onChange={handleChange} />
    {errors.email && <p className="error">{errors.email}</p>}

    <input
      name="password" type="password"
      value={form.password} onChange={handleChange}
    />
    {errors.password && <p className="error">{errors.password}</p>}

    <button type="submit">Зарегистрироваться</button>
  </form>
);

Как это всё связано

Цикл такой: пользователь печатает → handleChange обновляет form → жмёт «Отправить» → validate возвращает ошибки → setErrors показывает их под полями. Всё построено на уже знакомых вам кирпичиках: управляемые поля, состояние, события, условный рендеринг.

Итог

  • Форму с валидацией строят на двух состояниях: значения полей и объект ошибок.
  • Функция валидации возвращает объект ошибок; пустой объект означает «всё верно».
  • Ошибки выводят условно под полями; вся механика — это знакомые controlled inputs, состояние и события.
Проверьте себя
1. Как удобно хранить ошибки валидации формы?
AВ одной строковой переменной
BВ объекте состояния, где ключ — имя поля, значение — текст ошибки
CВ массиве зависимостей useEffect
DВ localStorage
2. Как по объекту ошибок понять, что форму можно отправлять?
Aerrors === null
BObject.keys(errors).length === 0 — в объекте нет ни одной ошибки
Cerrors === false
Derrors.length > 0
3. На каких уже изученных приёмах строится эта форма?
AНа классовых компонентах и наследовании
BНа управляемых полях, состоянии, событиях и условном рендеринге
CНа Context и useMemo
DТолько на useEffect
Поддержать проект