Легкая валидация форм в React

Когда вы сталкиваетесь с валидацией форм в React, вам не нужно сразу же тянуться к какой-нибудь библиотеке форм. Попробуйте встроенную валидацию форм с помощью API ограничений валидации — вы можете настроить внешний вид сообщений валидации и их содержание. Поиграйте с конечным результатом и ознакомьтесь с репозиторием примеров.

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

У вас на сайте есть простая форма. Возможно, это форма входа в систему или подписки на рассылку — несколько полей и кнопка отправки. У вас нет никакой сложной логики взаимодействия, поэтому просто возьмите содержимое формы с помощью FormData в обработчике onSubmit и отправьте его на бэкенд.

Давайте создадим форму с одним полем электронной почты. Включим HTML-атрибуты для проверки на стороне клиента.

function onSubmit(e) {
  e.preventDefault();
  const formData = new FormData(e.currentTarget);
  // Do something with the data
  console.log(Object.fromEntries(formData.entries()));
}

function Form() {
  return (
    <form onSubmit={onSubmit}>
      <p>
        <label>
          Your e-mail
          <input type="email" name="email" required />
        </label>
      </p>
      <p>
        <button type="submit">Submit</button>
      </p>
    </form>
  );
}
Вход в полноэкранный режим Выход из полноэкранного режима

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

Отображение сообщения о проверке

Возможно, вам не нравится, как выглядит всплывающее окно браузера. Возможно, вы хотите, чтобы оно выглядело одинаково во всех браузерах, или вы хотите поместить ошибку валидации в другое место. В этот момент вы можете подумать о том, чтобы сделать логику валидации самостоятельно или обратиться к какой-нибудь библиотеке React forms.

Но API валидации Constraint предоставляет хорошую абстракцию для начала. В настоящее время он также хорошо поддерживается в браузерах.

Когда поле не проходит валидацию, оно вызывает событие invalid. Сообщение об ошибке можно прочитать из свойства validationMessage поля ввода.

function Input() {
  // Passed into input's onInvalid prop
  const invalidHandler = (e) => {
    // e.target is the input
    const validationMessage = e.target.validationMessage;
    // prints: 'Please fill out this field.'
    console.log(validationMessage);
  };

  return (
    <input onInvalid={invalidHandler} type="email" name="email" required />
  );
}
Вход в полноэкранный режим Выход из полноэкранного режима

Теперь, когда у нас есть доступ к этому сообщению, мы можем показать его пользователю. Например, мы можем сохранить его в локальном состоянии и отобразить. Но нам также нужно запретить браузеру показывать всплывающее сообщение — это делается с помощью e.preventDefault().

function Input(props) {
  const [validationMessage, setValidationMessage] = useState();
  const invalidHandler = (e) => {
    const validationMessage = e.target.validationMessage;
    setValidationMessage(validationMessage);
    e.preventDefault();
  };
  return (
    <>
      <input onInvalid={invalidHandler} type="email" name="email" required />
      <span className="validation-message">{validationMessage}</span>
    </>
  );
}
Вход в полноэкранный режим Выход из полноэкранного режима

В качестве бонуса мы также можем использовать псевдоклассы CSS для валидации ввода, такие как :required и :valid. К сожалению, псевдо-класс :invalid применяется ко всем полям сразу, в то время как более полезный псевдо-класс :user-invalid (который применяется к полям, с которыми взаимодействовал пользователь) поддерживается только Firefox.

Сброс состояния

В этом решении есть одна проблема: ошибка валидации отображается даже после того, как поле исправлено.

Это происходит потому, что обработчик invalid срабатывает только при отправке формы. Мы можем прослушивать дополнительные события поля, такие как blur или change, чтобы обновить или скрыть сообщение о валидации.

function Input(props) {
  const [validationMessage, setValidationMessage] = useState();
  const invalidHandler = (e) => {
    const validationMessage = e.target.validationMessage;
    setValidationMessage(validationMessage);
    e.preventDefault();
  };
  return (
    <>
      <input
        onInvalid={invalidHandler}
        onChange={invalidHandler}
        type="email"
        name="email"
        required
      />
      <span className="validation-message">{validationMessage}</span>
    </>
  );
}
Вход в полноэкранный режим Выйти из полноэкранного режима

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

Преимущества и недостатки

Если у вас небольшое количество простых форм, нативная HTML-валидация может быстро привести вас к пригодным для использования результатам.

Самыми большими преимуществами этого подхода являются меньшее количество зависимостей и прогрессивное улучшение — валидация будет работать, даже если клиент не сможет загрузить JavaScript. Возможно, это не очень важно для React, но вполне жизнеспособно, если вы используете рендеринг на стороне сервера (например, с помощью таких фреймворков, как Next.js или Remix). Только бэкенд должен быть в состоянии принять форму, отправленную без JavaScript.

С другой стороны, есть и некоторые недостатки.

Для начала, сообщения валидации по умолчанию учитывают локаль браузера, а не страницы. Результат может быть немного запутанным. Например, если вы используете пользовательский ввод pattern с пояснением, вы можете получить смешанные языки в сообщении о валидации (хотя кажется, что title отображается только в Firefox).

Разные браузеры предоставляют разные сообщения валидации, поэтому если вам нужен жесткий контроль над копированием, вы должны предоставлять сообщения самостоятельно. Вы можете прочитать свойство validity поля, которое дает вам состояние валидности. Статья об API валидации ограничений из CSS Tricks включает удобную функцию hasError для начала работы. С другой стороны, большинство библиотек выдают одинаковые сообщения о валидности во всех браузерах.

Поскольку API валидации ограничений привязан к HTML, сложнее поделиться логикой валидации с бэкендом. Например, библиотека Formik forms использует библиотеку Yup для валидации данных. Вы можете использовать одну и ту же схему валидации как на клиенте, так и на сервере.

Для приложения с большим количеством форм я бы без колебаний выбрал какую-нибудь популярную библиотеку, например, React Hook Form, React Final Form или Formik. Но для простого сайта с единственной формой «Свяжитесь с нами»? Я бы постарался не усложнять.

Ресурсы

  • Серия статей Forms Validation на CSS Tricks была чрезвычайно ценным ресурсом, несмотря на то, что она немного устарела. Особенно часть 2 углубляется в JavaScript-логику валидации форм.
  • MDN предоставляет актуальный учебник по валидации форм на стороне клиента с использованием ванильного JavaScript.
  • Если вы хотите узнать больше об использовании FormData в React, прочитайте статьи FormData with React Hooks and Fetch от Matt Boldt и Creating forms in React in 2020 от Kristofer Selbekk.

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