Валидация форм в React

в 9:16, , рубрики: form validation, React, ReactJS, метки:

Если вы когда-нибудь пользовались фреймворком AngularJS, то вы знаете, как легко в нем валидируются формы. Однако в React ситуация несколько хуже. Оно и понятно, ведь это всего лишь библиотека. Но благодаря сообществу из этой библиотеки можно сделать мощное средство для создания полноценных SPA-приложений. На данный момент создано огромное множество компонентов, которые способны удовлетворить большинство нужд разработчиков на React. В данной статье я бы хотел описать подход, который использовал для валидации форм с помощью компонента Formsy-react.

Начну с того, что компонентов для валидации форм существует достаточно много (здесь представлено 32). Я попробовал некоторые из них и решил остановиться именно на Formsy, так как он выглядел не слишком замудреным и при этом достаточно гибким. Принцип работы я покажу на примере формы логина. Чтобы не заморачиваться со стилями, будем использовать react-bootstrap.

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

Итак, у нас есть компонент Login, который и отвечает за нашу форму. В нем есть 3 различных способа логина, соответственно, удобно было бы отобразить их с помощью вкладок:

Исходный код вкладок с полями ввода

<Tab.Pane eventKey="login">
  <Formsy.Form onValidSubmit={this.handleLogin} onValid={this.enableButton} onInvalid={this.disableButton}>

  <FormGroup>
    <ControlLabel>Login</ControlLabel>
      <TextInput name="login" type="text" validations={{minLength: 5}} validationErrors={{minLength: 'Enter at least 5 sumbols'}} required/>
    </FormGroup>

    <FormGroup>
      <ControlLabel>Password</ControlLabel>
        <TextInput name="loginPassword" type="password" validations={{strongPassword: validations.strongPassword}} validationErrors={{strongPassword: "Enter a strong password! At least 6 symbols"}} required/>
    </FormGroup>

    <FormGroup>
      <Button type="submit" bsStyle="primary" disabled={!this.state.isButtonEnabled} block>Login</Button>
    </FormGroup>

    </Formsy.Form>
</Tab.Pane>

<Tab.Pane eventKey="email">
  <Formsy.Form onValidSubmit={this.handleLogin} onValid={this.enableButton} onInvalid={this.disableButton}>

    <FormGroup>
      <ControlLabel>Email</ControlLabel>
        <TextInput name="email" type="text" validations={{isGoogleEmail: validations.isGoogleEmail}} validationErrors={{isGoogleEmail: 'Only Gmail boxes are accepted'}} required/>
    </FormGroup>

    <FormGroup>
      <ControlLabel>Password</ControlLabel>
      <TextInput name="loginPassword" type="password" validations={{strongPassword: validations.strongPassword}} validationErrors={{strongPassword: "Enter a strong password! At least 6 symbols"}} required/>
    </FormGroup>

    <FormGroup>
      <Button type="submit" bsStyle="primary" disabled={!this.state.isButtonEnabled} block>Login</Button>
    </FormGroup>

  </Formsy.Form>
</Tab.Pane>

<Tab.Pane eventKey="phone">
  <Formsy.Form onValidSubmit={this.handleLogin} onValid={this.enableButton} onInvalid={this.disableButton}>

    <FormGroup>
      <ControlLabel>Phone</ControlLabel>
      <TextInput name="phone" type="tel" validations={{isPhoneNumber: validations.isPhoneNumber, containsPlusPrefix: validations.containsPlusPrefix}} validationErrors={{isPhoneNumber: 'You should enter a valid phone number', containsPlusPrefix: 'Enter your number without +'}} required/>
    </FormGroup>

    <FormGroup>
      <ControlLabel>Password</ControlLabel>
      <TextInput name="phonePassword" type="password" validations={{strongPassword: validations.strongPassword}} validationErrors={{strongPassword: "Your password should contain at least 1 number, 1 lowercase letter, 1 uppercase letter"}} required/>
    </FormGroup>

    <FormGroup>
      <Button type="submit" bsStyle="primary" disabled={!this.state.isButtonEnabled} block>Login</Button>
    </FormGroup>

  </Formsy.Form>
</Tab.Pane>

Каждая вкладка представляет из себя форму, внутри которой лежит 2 поля и кнопка для отправки формы.

Начнем по порядку, с компонента Formsy.Form. В нем нас интересует 3 свойства (props): onValidSubmit, onValid, onInvalid.

Свойство onValidSubmit отвечает за отправку формы. Если все данные введены корректно и пользователь нажимает кнопку логин, то происходит вызов функции this.handleLogin, которая отправляет данные на сервер. Эта функция должна иметь один параметр, который будет содержать в себе объект. В этом объекте хранятся названия полей и их значения.

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

Далее у нас есть поля, которые необходимо проверять на валидность введенных данных. Для нормального функционирования данного компонента, нам необходимо создать собственный компонент для ввода данных (TextInput). На сайте Formsy можно найти готовый компонент, который включает в себя все что нужно и требует минимум изменений перед использованием. В наш компонент необходимо передать все стандартные свойства для тега input, такие как type и пр, а также несколько специальных свойств, которые помогут с валидацией компонента.

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

Также необходимо обозначить свойство validations. В данном свойстве ожидается объект. В компоненте Formsy уже заложены некоторые валидации, например, minLength, которую я использовал в поле логин. Не сложно догадаться, что с помощью этой проверки мы можем установить минимальное число введенных символов. Есть и много других встроенных валидаций, например, на проверку корректности адреса электронной почты, телефона и другие. Однако, этот компонент не был бы так хорош, если бы нельзя было создавать собственные функции проверки. И это возможно!

Например, в поле с вводом электронной почты я объявил собственную проверку того, что человек вводит адрес электронной почты, зарегистрированный на gmail.com. Функция проверки выглядит следующим образом:

Исходный код функции проверки

function isGoogleEmail(values, value) {
  if (typeof value !== 'undefined' && value.indexOf('gmail.com') === -1) {
    return false;
  }
  return true;
}

Функция принимает в себя 2 параметра: все поля формы и текущее поле, которое проходит проверку. Первый параметр содержит массив всех полей и их значений, которые присутствуют в форме. Во втором параметре value содержится содержимое текущего поля. Внутри функции обязательно нужно проверить, существует ли value, а также произвести любые другие проверки. Если функция возвращает false, значит проверка не прошла и пользователь не сможет отправить форму. В обратном случае все ок, данное поле прошло проверку и не содержит ошибок

Второе свойство, которое мы должны передать в поле ввода — validationErrors. Вся прелесть этого свойства в том, что для каждой ошибки оно будет выдавать свое сообщение. Таким образом, можно повесить на одно поле разные проверки (например, кол-во введенных символов, наличие хотя бы одного специального символа и пр) и для каждой из этих проверок выдавать свою ошибку (а не писать в одном сообщении о том, что поле должно содержать минимум 8 символов, 2 цифры, 3 буквы и пр). Данный подход используется в поле для ввода телефона, где вначале происходит «супер надежная проверка» на то, что введенный текст действительно является телефоном, а потом проверяется, не стоит ли в начале '+'.

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

Спасибо за внимание!

Автор: theWaR_13

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js