Валидация/отправка формы в ванильном React (без библиотек)


Валидация/подтверждение формы в ванильном React (без библиотек)

Вам не нужна модная библиотека, когда у вас есть HTML5 и Constraint API.

Ссылка на вторую часть: не очень тривиальный пример


Официальная документация React предлагает 3 возможных способа обработки отправки/оценки формы:

  • Контролируемые компоненты
  • Неконтролируемые компоненты
  • Полнофункциональные решения (сторонние библиотеки).

Но ни один из этих трех способов не является для меня особенно привлекательным.

Контролируемые компоненты: Мне лично не нравятся управляемые компоненты, поскольку они предполагают ручное управление состоянием, что в большинстве случаев приводит к ненужным и неэффективным перерисовкам.

Неконтролируемые компоненты: Документация React предлагает реализовать неконтролируемые компоненты, используя ссылку для получения значений формы из DOM, но затем не предоставляет много информации о том, как лучше всего извлекать данные и проверять их.

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

В наши дни существует множество сторонних библиотек, которые делают именно это… но действительно ли нам нужна такая библиотека?


Цель

Давайте создадим простую форму, подобную этой:

Интерактивная демонстрация доступна здесь.

Мы хотим создать форму, удовлетворяющую следующим требованиям:

  • Имя и Email являются обязательными
  • Email должен представлять собой действительный адрес электронной почты
  • Адрес является необязательным, без ограничений
  • Tel необязателен, но если он введен, то должен представлять формально правильный номер телефона в Великобритании.

При отправке форма проходит проверку и должна показать ошибки проверки следующим образом:

В случае ошибок валидации фокус должен быть перемещен на первое недействительное поле.


HTML5 и API ограничений

(Источник MDN): HTML5 уже имеет возможность проверять большинство пользовательских данных без использования JavaScript. Для этого используются атрибуты валидации элементов формы.

  • required: Указывает, должно ли поле формы быть заполнено перед отправкой формы.
  • minlength и maxlength: Определяют минимальную и максимальную длину текстовых данных (строк).
  • min и max: Определяют минимальное и максимальное значение числовых типов ввода.
  • type: Указывает, должны ли данные быть числом, адресом электронной почты или другим определенным заданным типом.
  • pattern (шаблон): Указывает регулярное выражение, определяющее шаблон, которому должны соответствовать вводимые данные.

Если данные, введенные в поле формы, соответствуют всем правилам, указанным вышеперечисленными атрибутами, они считаются корректными. В противном случае они считаются недопустимыми.

Большинство браузеров поддерживают API Constraint Validation, который состоит из набора методов и свойств, позволяющих проверять значения, введенные пользователями в элементы управления формы, перед отправкой их на сервер.

Имея в своем распоряжении эти инструменты, мы можем создавать пользовательские компоненты для простого и эффективного управления формами.


Решение

Строительными блоками нашего решения являются следующие два пользовательских компонента:

  • <Form />.
  • <TextInput />

<Form />.

Ключевым атрибутом здесь является noValidate.

Атрибут novalidate отключает автоматические сообщения браузера об ошибках валидации. Без него наша форма выглядела бы примерно так:

Вся магия происходит в обратном вызове handleSubmit:

  • мы останавливаем отправку формы с помощью e.preventDefault()
  • мы записываем состояние валидности формы с помощью isValid
  • мы добавляем className «submitted» для улучшения UX (подробнее об этом в ближайшее время)
  • мы перемещаем фокус на первое недействительное поле, если таковое имеется
  • собираем данные формы и вызываем обратный вызов onSubmit, если форма действительна.

Последнее — еще один ключевой момент этого решения: сбор данных формы с помощью объекта FormData. Нет необходимости вручную перебирать элементы формы и извлекать их значения.

«Интерфейс FormData предоставляет возможность легко построить набор пар ключ/значение, представляющих поля формы и их значения» — (источник: MDN)

<TextInput />

Компонент TextInput отвечает за отображение поля ввода, метки и возможной ошибки валидации.

Код можно посмотреть здесь, но по сути этот компонент устанавливает внутреннюю переменную состояния со строкой ошибки валидации, полученной из API ограничений, и сбрасывает ее при размытии, если ошибка была исправлена:

Реализация

Код для реализации формы в примере выглядит следующим образом:

Что следует отметить:

  • Мы устанавливаем обязательный атрибут для Name и Email
  • type=»email» проверяет, что Constraint API проверяет, что вводимый адрес является действительным адресом электронной почты.
  • Адрес не требует правил валидации
  • Tel не является обязательным, но мы установили атрибут pattern для проверки ввода по regex (установка type=tel не обеспечивает встроенную проверку).

Всякий раз, когда нам нужно добавить другой файл в форму, мы просто добавляем новый TextInput и устанавливаем для него соответствующие атрибуты.

Не нужно обновлять схемы или добавлять еще один useState для отслеживания значения нового поля, давайте просто переложим всю тяжелую работу на встроенный API!

Улучшение UX

Последний штрих для улучшения UX — показывать ошибки валидации только после отправки формы.

Использование только псевдокласса :invalid в нашем CSS для стилизации неправильных полей привело бы к появлению красных выделенных полей ввода и сообщений об ошибках сразу же после загрузки страницы… а мы не хотим кричать пользователю в лицо, что его/ее данные введены неправильно, прежде чем он/она успеет ввести хоть один символ!

По этой причине мы добавляем к форме имя класса .submitted и оформляем TextInput таким образом:

i18n

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

Если вас устраивают сообщения по умолчанию, то вам больше не о чем беспокоиться: ваши английские, испанские, итальянские или китайские пользователи получат сообщения на своем родном языке.

Компонент TextInput, представленный в примере, также позволяет настраивать базовые сообщения валидации с помощью атрибута errorText:

Это просто пример, чтобы показать, как можно настроить эти сообщения.

Наконец

После того, как форма формально корректна, мы можем отправить ее в обратном вызове onSubmit.

Мы получаем объект FormData, который затем можно легко отправить с помощью метода fetch() или XMLHttpRequest.send(). Он использует тот же формат, что и форма, если тип кодировки установлен на "multipart/form-data", или мы можем преобразовать его в более привычный объект ключ/значение:

, чтобы получить следующее:

Заключительные слова

Есть красота в простоте, и валидация/отправка формы не становится намного проще, чем это ИМХО 🙂 .

Любые комментарии / отзывы будут очень признательны!

Ссылка на вторую часть: не такой уж тривиальный пример

Оцените статью
devanswers.ru
Добавить комментарий