Создание лучших форм React с помощью Formik

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

Вот пример базовой формы React, написанной без библиотек и с минимальным стилем Bootstrap:

Начальная загрузка React-формы

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

constructor(props) {
  super(props);
  this.state = {
    formValues: {
      email: "",
      password: ""
    },
    formErrors: {
      email: "",
      password: ""
    },
    formValidity: {
      email: false,
      password: false
    },
    isSubmitting: false
  };
}

Затем мы создаем метод рендеринга формы с входными значениями, полученными из состояния:

render() {
  const { formValues, formErrors, isSubmitting } = this.state;
  return (
    <div className="container">
      <div className="row mb-5">
        <div className="col-lg-12 text-center">
          <h1 className="mt-5">Login Form</h1>
        </div>
      </div>
      <div className="row">
        <div className="col-lg-12">
          <form onSubmit={this.handleSubmit}>
            <div className="form-group">
              <label>Email address</label>
              <input
                type="email"
                name="email"
                className={`form-control ${
                  formErrors.email ? "is-invalid" : ""
                }`}
                placeholder="Enter email"
                onChange={this.handleChange}
                value={formValues.email}
              />
              <div className="invalid-feedback">{formErrors.email}</div>
            </div>
            <div className="form-group">
              <label>Password</label>
              <input
                type="password"
                name="password"
                className={`form-control ${
                  formErrors.password ? "is-invalid" : ""
                }`}
                placeholder="Password"
                onChange={this.handleChange}
                value={formValues.password}
              />
              <div className="invalid-feedback">{formErrors.password}</div>
            </div>
            <button
              type="submit"
              className="btn btn-primary btn-block"
              disabled={isSubmitting}
            >
              {isSubmitting ? "Please wait..." : "Submit"}
            </button>
          </form>
        </div>
      </div>
    </div>
  );
}

Теперь нам нужно написать handleChange метод обновления состояния с помощью пользовательского ввода:

handleChange = ({ target }) => {
  const { formValues } = this.state;
  formValues[target.name] = target.value;
  this.setState({ formValues });
  this.handleValidation(target);
};

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

handleValidation = target => {
  const { name, value } = target;
  const fieldValidationErrors = this.state.formErrors;
  const validity = this.state.formValidity;
  const isEmail = name === "email";
  const isPassword = name === "password";
  const emailTest = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/i;
  validity[name] = value.length > 0;
  fieldValidationErrors[name] = validity[name]
    ? ""
    : `${name} is required and cannot be empty`;
  if (validity[name]) {
    if (isEmail) {
      validity[name] = emailTest.test(value);
      fieldValidationErrors[name] = validity[name]
        ? ""
        : `${name} should be a valid email address`;
    }
    if (isPassword) {
      validity[name] = value.length >= 3;
      fieldValidationErrors[name] = validity[name]
        ? ""
        : `${name} should be 3 characters minimum`;
    }
  }
  this.setState({
    formErrors: fieldValidationErrors,
    formValidity: validity
  });
};

Последней частью этой базовой формы является handleSubmit способ подачи заявки. Нам нужно проверить formValidity ценности, и если они есть false значения, снова запустите метод проверки, не отправляя форму.

handleSubmit = event => {
  event.preventDefault();
  this.setState({ isSubmitting: true });
  const { formValues, formValidity } = this.state;
  if (Object.values(formValidity).every(Boolean)) {
    alert("Form is validated! Submitting the form...");
    this.setState({ isSubmitting: false });
  } else {
    for (let key in formValues) {
      let target = {
        name: key,
        value: formValues[key]
      };
      this.handleValidation(target);
    }
    this.setState({ isSubmitting: false });
  }
};

Теперь форма готова к использованию. React предоставляет только уровень «представления» для вашего приложения, а это означает, что он предоставляет только основные потребности для создания компонентов формы. component, stateа также props похожи на блоки головоломки, которые вы должны собрать вместе, чтобы построить рабочую форму.

Как видите, для формы с двумя текстовыми полями достаточно много кода. Представьте, сколько значений состояния вам нужно отслеживать в форме с 10 или более входными данными. Ой!

Да, создавать формы с помощью React неинтересно; это очень многословно и жестко. Построение формы и создание метода проверки — скучные задачи. В каждой форме вам нужно будет сделать как минимум следующее:

  1. Настройка состояния для значений формы, ошибок формы и действительности формы
  2. Обработка пользовательского ввода и обновление состояния
  3. Создание функций проверки
  4. Обработка представления

Создание форм естественным способом «React» требует, чтобы вы написали каждую часть процесса от настройки состояний до отправки формы. Я сделал бесчисленное количество форм React, и я всегда нахожу эту часть создания форм очень скучной и трудоемкой. К счастью, я не единственный, кто так себя чувствует.

Введите Формик

Джаред Палмер создал библиотеку Formik из-за разочарования при создании форм React. Ему нужен был способ стандартизировать компоненты ввода и процесс отправки форм. Formik поможет вам написать три самые раздражающие части построения формы:

  1. Получение значений в состоянии формы и вне его
  2. Проверка и сообщения об ошибках
  3. Обработка отправки формы

Вот снова та же форма, но на этот раз с использованием Formik:

Пример формы Formik

Эта новая форма использует только четыре дополнительных компонента из библиотеки Formik: <Formik />, <Form />, <Field />а также <ErrorMessage />. Чтобы разблокировать силу Формика, вы можете обернуть свою форму внутри <Formik /> составная часть:

<Formik>
  <Form>
    {/* the rest of the code here */}
  </Form>
</Formik>

Давайте посмотрим, как Formik упрощает создание форм по сравнению с естественным способом React.

Получение значений в состоянии формы и вне его

Formik внутренне настроит состояние для хранения пользовательского ввода через свой initialValues prop, поэтому вам больше не нужно инициализировать состояние из конструктора.

Чтобы получить значения во внутреннем состоянии Formik и из него, вы можете использовать <Field /> компонент для замены обычного HTML <input /> составная часть. Этот компонент будет творить чудеса, синхронизируя состояние Formik и входное значение, поэтому вам не нужно передавать value а также onChange реквизит в <Field /> составная часть:

<Formik
  initialValues={{ email: "", password: "" }}
  onSubmit={({ setSubmitting }) => {
    alert("Form is validated! Submitting the form...");
    setSubmitting(false);
  }}
>
  {() => (
    <Form>
      <div className="form-group">
        <label htmlFor="email">Email</label>
        <Field
          type="email"
          name="email"
          className="form-control"
        />
      </div>
      <div className="form-group">
        <label htmlFor="password">Password</label>
        <Field
          type="password"
          name="password"
          className="form-control"
        />
      </div>
    </Form>
  )}
</Formik>

С Formik нет необходимости инициализировать состояние в constructor и создать свой собственный handleChange метод больше. Обо всем позаботятся.

Проверка и сообщения об ошибках

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

Сравните этот код между проверкой Formik и проверкой vanilla React:

// Formik validation code. Take values from Formik
validate={values => {
  let errors = {};
  if (values.email === "") {
    errors.email = "Email is required";
  } else if (!emailTest.test(values.email)) {
    errors.email = "Invalid email address format";
  }
  if (values.password === "") {
    errors.password = "Password is required";
  } else if (values.password.length < 3) {
    errors.password = "Password must be 3 characters at minimum";
  }
  return errors;
}}

// Vanilla React validation code. Take values given by handleChange
handleValidation = target => {
  const { name, value } = target;
  const fieldValidationErrors = this.state.formErrors;
  const validity = this.state.formValidity;
  const isEmail = name === "email";
  const isPassword = name === "password";
  const emailTest = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/i;
  validity[name] = value.length > 0;
  fieldValidationErrors[name] = validity[name]
    ? ""
    : `${name} is required and cannot be empty`;
  if (validity[name]) {
    if (isEmail) {
      validity[name] = emailTest.test(value);
      fieldValidationErrors[name] = validity[name]
        ? ""
        : `${name} should be a valid email address`;
    }
    if (isPassword) {
      validity[name] = value.length >= 3;
      fieldValidationErrors[name] = validity[name]
        ? ""
        : `${name} should be 3 characters minimum`;
    }
  }
  this.setState({
    formErrors: fieldValidationErrors,
    formValidity: validity
  });
};

Теперь, когда проверка завершена, вам нужно вывести сообщения об ошибках. Формик <ErrorMessage /> компонент автоматически отобразит сообщение об ошибке для <Field /> компонент с заданным именем. Вы можете настроить, какой HTML-тег будет отображаться через component опора Поскольку в этом примере формы используется стиль Bootstrap, вам нужно будет добавить className тоже опора:

// Formik error message output
<Field
  type="email"
  name="email"
  className={`form-control ${
    touched.email && errors.email ? "is-invalid" : ""
  }`}
/>
<ErrorMessage
  component="div"
  name="email"
  className="invalid-feedback"
/>

// Vanilla React error message output
<input
  type="email"
  name="email"
  className={`form-control ${
    formErrors.email ? "is-invalid" : ""
  }`}
  placeholder="Enter email"
  onChange={this.handleChange}
  value={formValues.email}
/>
<div className="invalid-feedback">{formErrors.email}</div>

Код для сообщения об ошибке на самом деле примерно такой же, но в валидации Formik намного меньше кода, чем в vanilla React. Молодец, Формик!

Еще более простая проверка с Yup

Хотя вы уже чувствуете преимущества использования Formik в процессе проверки, вы можете сделать его еще проще, используя средство проверки схемы объекта.

Валидатор схемы объекта — это просто библиотека, которая позволяет вам определить схему объекта JavaScript и убедиться, что значения объекта соответствуют этой схеме в процессе проверки. Это особенно полезно при проверке данных формы, поскольку на самом деле это объект, хранящийся внутри Formik. values опора

Теперь одной из таких библиотек является Yup, и автор Formik так любит Yup, что включил специальную опору, которая связывает Yup с Formik под названием validationSchema. Этот реквизит автоматически преобразует ошибки проверки Yup в красивый объект, чьи ключи совпадают. values а также touched.

Вот пример Formik, использующий Yup в качестве схемы проверки. Обратите внимание, как реквизит проверки удаляется из <Formik /> составная часть:

Formik с примером Yup

С валидатором схемы объектов Yup вам не нужно вручную писать if условия больше. Вы можете узнать больше о Yup и о том, какую проверку он может выполнять, на посещение репозитория GitHub.

Процесс отправки формы

Формик <Form /> компонент автоматически запустит ваш метод проверки и отменит процесс отправки, если есть какие-либо ошибки. В то время как вы должны включить поддержку onSubmit в обычный <form /> элемент, Формик <Form /> оболочка будет запускать onSubmit prop функция, которую вы передали в <Formik /> составная часть:

// Formik's submit code. Won't be executed if there are any errors.
onSubmit={({ setSubmitting }) => {
  alert("Form is validated!");
  setSubmitting(false);
}}

// Vanilla React submit code. Check on validity state then run validation manually.
handleSubmit = event => {
  event.preventDefault();
  this.setState({ isSubmitting: true });
  const { formValues, formValidity } = this.state;
  if (Object.values(formValidity).every(Boolean)) {
    alert("Form is validated!");
    this.setState({ isSubmitting: false });
  } else {
    for (let key in formValues) {
      let target = {
        name: key,
        value: formValues[key]
      };
      this.handleValidation(target);
    }
    this.setState({ isSubmitting: false });
  }
};

Для отправки Formik требуется как минимум четыре строки кода, и вам не нужно отслеживать достоверность входных данных формы. Это довольно аккуратно!

Но как насчет редукционной формы?

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

Подумайте об этом: значение текстового поля имени пользователя имеет какое-то значение для вашего приложения в глобальном масштабе? Если нет, то действительно не нужно отслеживать его значение с помощью Redux. Даже пророк Дэн Абрамов сказал то же самое.

Другая проблема с redux-form заключается в том, что вы сохраняете входные значения формы в хранилище Redux. Это означает, что ваше приложение будет вызывать редьюсер Redux при каждом нажатии клавиши, чтобы обновить значение только одного текстового поля. Не хорошая идея.

Я люблю писать формы в стиле «Formik», но если вы предпочитаете редукционную форму, то это тоже нормально. 😉

Вывод

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

Formik определенно является одной из тех библиотек с открытым исходным кодом, которая необходима, если вы пишете много форм в своем приложении React. Это действительно ускоряет процесс разработки и сокращает шаблонный код за счет абстрагирования частей формы с помощью таких компонентов, как <Field /> а также <Form />.

В то время как ванильная форма React требует, чтобы вы указали свои собственные значения состояния и методы, вы можете просто передать свойства в <Formik /> компонент для выполнения тех же действий: обработки ввода пользователя, проверки ввода и отправки форм.

Если вы хотите узнать больше о Formik, перейти к документации или посмотрите представленную ниже презентацию ее создателя.

Формик Презентация

Выпущен React Distilled 2.0

Если вы хотите узнать больше о React и о том, как его использовать для создания полноценного веб-приложения с нуля, я предлагаю скидку 28 % на мою книгу. Реагировать на перегонку чтобы отпраздновать его выпуск (от 49 до 34 долларов).

Он включает новые главы, посвященные React Context API и React Hooks, и показывает, как можно создать приложение React, используя только React и Firestore.

Идти возьми это сейчас так что вы можете стать React Genius уже сегодня!

1_VEWXDp2iflV30wSyBBfEPA.png


Первоначально опубликовано 28 июня 2019 г.

Похожие записи

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *