Видеоуроки, интерактивный редактор и сохранение прогресса — бесплатно, сразу после входа.
ВойтиСоздать аккаунт — бесплатноЗакончили урок?
Войдите, чтобы отмечать прогресс
В этом решении мы создаём контактную форму с полной валидацией полей и обработкой отправки.
Вместо создания отдельного состояния для каждого поля, мы храним все данные формы в одном объекте. Это упрощает работу - у нас одна функция обновления для всех полей. Поле subject имеет начальное значение 'question', потому что это значение по умолчанию в select. Поле agree - булево, потому что это checkbox.
Мы извлекаем несколько свойств из e.target (элемента, который вызвал событие) за один раз. name - это атрибут поля (например, "email"), value - текущее значение, type - тип input (например, "checkbox"), checked - состояние чекбокса. Деструктуризация делает код короче.
Квадратные скобки [name] говорят JavaScript использовать значение переменной как ключ объекта. Если name === "email", это эквивалентно email: value. Это позволяет одной функции обновлять любое поле формы - мы не пишем отдельную функцию для каждого поля.
Checkbox работает иначе чем обычные поля. У него нет value в привычном смысле - вместо этого есть checked (true/false). Мы проверяем тип поля и для checkbox используем checked, для остальных - value. Без этого checkbox не работал бы корректно.
Когда пользователь начинает исправлять поле с ошибкой, мы сразу убираем сообщение об ошибке. Это улучшает пользовательский опыт - не нужно видеть красное сообщение, пока вводишь правильное значение. Мы создаём новый объект ошибок, заменяя ошибку текущего поля на пустую строку.
Метод trim() удаляет пробелы в начале и конце строки. Строка из одних пробелов после trim() станет пустой. Оператор ! превращает пустую строку в true. Это предотвращает отправку полей, заполненных только пробелами.
Регулярное выражение /\S+@\S+\.\S+/ проверяет базовую структуру email: непробельные символы, затем @, снова символы, точка и символы после неё. \S означает "не пробел", + означает "один или более". Метод test() возвращает true, если строка соответствует паттерну. Оператор ! инвертирует результат - мы проверяем, что email НЕ соответствует формату.
Мы сначала удаляем пробелы с trim(), затем проверяем длину. Это гарантирует, что 10 пробелов не пройдут валидацию. Проверка длины находится в блоке else if после проверки на пустоту, поэтому выполняется только если поле не пустое.
Object.keys() возвращает массив ключей объекта. Если объект ошибок пустой (нет ошибок), длина массива будет 0. Это универсальный способ проверить, пустой ли объект. Если ошибок нет, помечаем форму как отправленную, иначе сохраняем ошибки для отображения.
Метод preventDefault() отменяет стандартное поведение браузера - перезагрузку страницы при отправке формы. Без него страница перезагрузится и все данные в состоянии потеряются. Это первое, что нужно сделать в обработчике submit.
Когда форма успешно отправлена, мы показываем сообщение благодарности вместо самой формы. Ранний return завершает функцию - код с формой ниже не выполняется. Это чистый способ полностью изменить содержимое компонента.
Событие onSubmit срабатывает при отправке формы - это может быть клик на кнопку type="submit" или нажатие Enter в любом поле. Обработчик на <form>, а не на кнопке, захватывает все способы отправки.
Атрибут name должен совпадать с ключом в объекте formData. value связывает поле с состоянием, onChange обновляет состояние. Атрибут name критически важен - он говорит handleChange, какое поле обновлять через вычисляемое свойство [name].
Если для поля есть ошибка, добавляем класс error. CSS использует этот класс для выделения поля красной рамкой или изменения цвета. Это визуальная индикация проблемы, которую пользователь видит ещё до чтения текста ошибки.
Если для поля есть ошибка, показываем её текст под полем. Оператор && рендерит сообщение только если ошибка существует. Каждое поле имеет своё собственное место для ошибки, поэтому пользователь видит проблему рядом с нужным полем.
Select работает так же, как input - атрибуты name, value, onChange. Значение value на <select> определяет выбранную опцию по её value. React автоматически выберет <option> с соответствующим значением. Обработчик handleChange работает и для select без изменений.
Textarea в React работает как обычный input - значение задаётся через атрибут value, а не как дочерний контент (в HTML вы пишете <textarea>текст</textarea>). Это делает все поля формы единообразными - один и тот же паттерн value/onChange для всех.
Для checkbox используем checked вместо value. Атрибут id на input и htmlFor на label связывают их - клик по тексту label активирует checkbox. В React атрибут называется htmlFor (не for), потому что for - зарезервированное слово в JavaScript.