Skip to content

Latest commit

 

History

History
182 lines (149 loc) · 7.36 KB

File metadata and controls

182 lines (149 loc) · 7.36 KB

Валидация

На курсе "JavaScript. Профессиональная разработка веб-интерфейсов" вы использовали для валидации форм библиотеку PristineJS, на курсах "JavaScript. Архитектура клиентских приложений" и "React. Разработка сложных клиентских приложений" реализовывали валидацию самостоятельно. Здесь, в грейдировании, мы смешаем оба подхода – реализуем валидации с помощью React Hook Form.

Библиотека вам не знакома, поэтому разберём основные возможности на сравнении с PristineJS. Для примера завалидируем форму входа:

<form>
    <p>
        <label>Эл.почта:</label>
        <br />
        <input type="email" />
    </p>
    <p>
        <label>Пароль:</label>
        <br />
        <input type="password" />
    </p>
    <p>
        <label>
            <input type="checkbox" />
            Запомнить меня
        </label>
    </p>
    <button>Войти</button>
</form>

В случае с PristineJS будет достаточно расставить верно атрибуты в HTML:

<form class="login-form">
    <p>
        <label>Эл.почта:</label>
        <br />
        <input type="email" name="email" required />
    </p>
    <p>
        <label>Пароль:</label>
        <br />
        <input type="password" name="password" required />
    </p>
    <p>
        <label>
            <input type="checkbox" name="remember" />
            Запомнить меня
        </label>
    </p>
    <button>Войти</button>
</form>

И "скормить" форму библиотеке:

const form = document.querySelector(".login-form");

const pristine = new Pristine(form);

form.addEventListener('submit', (evt) => {
    evt.preventDefault();
    
    if (pristine.validate()) {
        // ....
    }
});

В случае с React Hook Form принцип действия похожий, только всё происходит в одном файле, в JSX:

import { useForm } from 'react-hook-form';

export default function Form() {
  const onSubmit = (evt) => evt.preventDefault();

  const { register, handleSubmit } = useForm();

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <p>
        <label>Эл.почта:</label>
        <br />
        <input type="email" {...register("userEmail", { required: true })} />
      </p>
      <p>
        <label>Пароль:</label>
        <br />
        <input type="password" {...register("userPassword", { required: true })} />
      </p>
      <p>
        <label>
          <input type="checkbox" />
          Запомнить меня
        </label>
      </p>
      <button>Войти</button>
    </form>
  );
}

Обратите внимание на разницу, вместо передачи библиотеке формы целиком const pristine = new Pristine(form); мы передаём каждое отдельное поле, используя функцию register() из хука useForm()<input type="email" {...register("userEmail", { required: true })} />.

В register() первым аргументом нужно передать уникальное имя, тот же атрибут name. Вторым аргументом можно передать объект с параметрами валидации, один в один как в штатных HTML-валидациях. Мы передаем required: true потому как поля почта и пароль у нас обязательные.

А вместо проверки if (pristine.validate()) в обработчике события submit, мы передаём наш обработчик отправки в функцию handleSubmit()<form onSubmit={handleSubmit(onSubmit)}>. React Hook Form сама вызовет его, если форма будет валидна.

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

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

return (
    <form onSubmit={handleSubmit(onSubmit)}>
        <p>
            <label>Эл.почта:</label>
            <br />
            <input
                type="email"
                {...register("userEmail", { required: true })}
+                aria-invalid={errors.userEmail ? "true" : "false"}
            />
+            {errors.userEmail?.type === 'required' && <><br/><span role="alert">"Укажите почту"</span></>}
        </p>

Причем код можно слегка упростить, если текст ошибки хранить сразу в register():

return (
    <form onSubmit={handleSubmit(onSubmit)}>
        <p>
            <label>Эл.почта:</label>
            <br />
            <input
                type="email"
-                {...register("userEmail", { required: true })}
+                {...register("userEmail", { required: "Укажите почту" })}
                aria-invalid={errors.userEmail ? "true" : "false"}
            />
-            {errors.userEmail?.type === 'required' && <><br/><span role="alert">"Укажите почту"</span></>}
+            {errors.userEmail && <><br/><span role="alert">{errors.userEmail?.message}</span></>}
        </p>

А что если возможностей штатных HTML-валидаций не хватает? В функцию register() в объект с параметрами валидации можно передать поле validate и описать там все необходимые проверки.

PristineJS:

const form = document.querySelector(".login-form");
const mail = form.querySelector("input[type=\"email\"]");

const pristine = new Pristine(form);

const checkMagicEmail = (value) => { ... };

pristine.addValidator(mail, checkMagicEmail, "Укажите волшебную почту");

React Hook Form:

const checkMagicEmail = (value) => { ... };

<input
    type="password"
    {...register(
        "userPassword",
        {
            required: "Укажите волшебную почту",
            validate: {
                checkMagicEmail
            }
        }
    )}
/>

Существует другой способ – валидация по схеме – но в вашем проекте он не пригодится. Как и прочие сложные вещи из React Hook Form. Однако вы всегда можете ознакомиться с ними в качестве доп.нагрузки в документации.