React + Formik + Yup + [CSS] = Простая + стилизованная форма.

Как разработчик React, у вас есть множество вариантов создания форм в приложении. Для простого одноразового использования вы можете решить запачкать руки, напрямую создав компонент-оболочку формы. Однако, если вам нужно несколько форм, вы можете использовать стороннюю библиотеку, такую ​​как Formik.

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

Необработанные формы HTML5

HTML5 + ванильный JavaScript отлично работает, пока форма не станет слишком большой. Как правило, вы будете использовать элементы ввода вложенной формы, такие как text, button, password, textarea и другие.

В конце вы добавляете кнопку «отправить», которая проверяет, а затем обрабатывает форму.

<form>
  <label htmlFor="emailAddress">Enter email:</label>
  <input type="text" name="emailAddress" />
  <label htmlFor="password">Password:</label>
  <input type="password" name="password" />
  <input type="submit" value="Submit" />
</form>

Атрибут name определяет поле, заполняемое пользователем. Это «требуется», когда вы отправляете форму на обработку сервером с использованием атрибута form action.

Однако, если вы проверяете и обрабатываете форму в JavaScript, вы можете использовать атрибут name для идентификации поля в вашем onchange обработчике.

// <input type="text" name="emailAddress"
//      onchange="handleChange"/>
function handleChange(e) {// included using <script>
  if (e.target.name === 'emailAddress')
    console.log("emailAddress changed");
}

Предостережения, связанные с необработанными формами HTML5

  • Проверка формы: изначально JavaScript был создан для проверки формы на стороне клиента. Скорее всего, вам это понадобится и для ваших форм. Однако реализация универсальной проверки формы - пустая трата времени, поскольку она уже реализована в сторонних библиотеках.
  • Шаблонный код: вы создадите много шаблонного кода с формами. Например, для каждого поля потребуются обработчики onchange и onblur, а затем сообщения об ошибках под ним. Код для формы входа может легко содержать до 500 строк кода (без стилизации).

Реагировать на формы

ReactJS - идеальное решение для форм HTML5. Ведь его основная цель - синхронизировать DOM браузера с вашими данными. Вы можете создать компонент-оболочку формы, который хранит значения полей в своем состоянии. Следовательно, проверка и отправка формы отделены от фактической разметки формы.

Чтобы значения полей оставались в состоянии компонента-оболочки, вам необходимо сделать компонент «управляемым».

«В HTML элементы формы обычно поддерживают свое собственное состояние и обновляют его на основе ввода данных пользователем. В React изменяемое состояние обычно сохраняется в свойстве состояния компонентов и обновляется только с помощью setState(). Мы можем объединить их, сделав состояние React «единственным источником истины».

- React Docs

Как сделать «единый источник истины»? Это достигается путем управления значением каждого ввода - с помощью onChange для установки значения в нашем состоянии React. Затем привяжите состояние ввода к состоянию React.

class LoginForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      username: '',
      password: '',
      errors: {
        username: '',
        password: ''
      }
    }
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }
  validateUsername(s) {
    // returns true/false based on user-name validity
  }
  validatePassword(s) {
    // returns true/false based on password validity
  }
  handleChange(e) {
    if (e.target.name === 'username') {
      this.state.username = e.target.value;
      if (!validateUsername(e.target.value))
        this.state.errors.username = "Invalid username";
    } else if (e.target.name === 'password') {
      this.state.password = e.target.value;
      if (!validatePassword(e.target.value))
        this.state.errors.password = "Invalid password";
    }
  }
  render() {// finally
    return (
      <form>
        <input type="text" onChange={{this.handleChange}} value={this.state.username} />
        <span>{this.errors.username}</span>
        <input type="password" onChange={{this.handleChange}} value={this.state.password} />
        <span>{this.errors.password}</span>
      </form>
    );
  }
}

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

  • Редактировать вводимые пользователем: вы можете исправить ввод, перехватив новое значение в handleChange.
this.state.username = e.target.value.toUpperCase();
  • Проверить наличие ошибок / доступность

Неконтролируемые компоненты

Вместо того, чтобы делать состояние React «единственным источником истины», вы можете сделать DOM «единственным источником истины», используя неконтролируемые компоненты. Здесь вы не обновляете состояние в handleChange, а всегда ссылаетесь на входной узел DOM, чтобы получить значение.

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

class LoginForm {
  constructor(props) {
    super(props);
    this.usernameRef = React.createRef();
  }
  render() {
    return (
      <form>
        <input ref={this.usernameRef} />
      </form>
    );
  }
}

Свойство usernameRef хранит визуализированный узел input DOM.

Формик спешит на помощь

Джаред Палмер, создатель Formik, написал библиотеку для стандартизации компонентов упаковки форм. Это сокращает количество стандартного кода, связанного с формами, и позволяет вам сосредоточиться на других аспектах вашего дизайна.

«Имея около 30 уникальных форм, быстро стало очевидно, что мы можем извлечь выгоду из стандартизации не только наших входных компонентов, но и способа передачи данных через наши формы». - Джаред Палмер

Концепция

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

Я приведу самый минимальный пример, который поможет вам понять процесс.

<Formik
    initialValues={{
      username: '',
      password: ''
    }}
    validationSchema={/* We'll discuss this below! */}
    validate={/* We'll discuss this below!*/}
    onSubmit={/* We'll discuss this shortly! */}
    render={({handleChange, onSubmit, values, errors}) => (
      <form>
        <input type="text" name="username" onChange={handleChange} value={values.username}/>
        {errors.username}
        <input type="password" name="password" onChange={handleChange} value={values.password} />
        {errors.password}
        <input type="button" onClick={onSubmit} value=")} />
      </form>
    )}
/>

Самым важным из приведенного выше кода является опора render. render prop должен быть функцией, которая принимает объект props, заданный Formik. Он возвращает компонент React, который является вашей формой. Есть полный список реквизита, предоставленный Formik; однако вы можете объявить поля, которые вы будете использовать.

  • values: Это сопоставление имени поля и значения поля. Его начальное значение задается заданным параметром initialValue.
  • handleChange: Этот обработчик событий делает то же, что и мы в нашем настраиваемом компоненте формы React. Он обновляет объект values, когда пользователь вводит что-то новое.
  • onSubmit: Это предоставляемая вами функция, которая отправляет форму с заданными значениями.

Реквизиты, которые вы должны предоставить:

  • validate / validationSchema: validate - это функция, которая возвращает любые ошибки в значениях формы. Он возвращает объект, который отображает имена полей в сообщения об ошибках. Альтернативный вариант - использовать Yup, библиотеку проверки схемы объекта. validationSchema - это объект, который происходит от Yup.

Да в смеси

Джаред Палмер рекомендует Yup в качестве инструмента проверки. Это из-за его удобства и ясности.

Пример схемы, созданной из Yup:

// npm install --save yup
import * as Yup from 'yup'
const loginSchema = Yup.object().shape({
  username: Yup.string()
    .email('Username should be an email)
    .required('Username is required!'),
  password: Yup.string()
    .required('Password is required!')
};

Вы можете validationSchema={loginSchema}, и тогда ошибки будут обновляться автоматически, когда пользователь вводит / обновляет ввод. Они будут отображаться через текстовые узлы.

Создание вашей первой формы

В формах, которые мы разработали до сих пор, мы не указывали пользователям, что и как заполнять. Мы должны добавить ярлыки и визуально оформить нашу форму, чтобы она выглядела привлекательно. Мне сложно построить что-то, что выглядело бы «потрясающе»; однако как разработчик мы могли бы создать что-то достойное. Конструкция не так проста, как кажется.

Также важно знать, что метки всегда выравниваются по правому краю. Он образует осевую линию посередине. Это фактически изучали даже разработчики Google, и это помогает пользователю быстрее заполнять форму.

Форма, которую я показал, использует таблицу и выравнивает комбинации надписей / текстовых полей в каждой строке. Кроме того, я использовал CSS для стилизации каждого элемента. Шаблон формы внутри компонента Formik будет выглядеть примерно так:

<form className="blackbox-form">
  <table>
  <tbody>
  <tr>
    <td>
      <label htmlFor="emailAddress">E-mail Address</label>
    </td>
    <td>
      <input name="emailAddress" type="text" onChange={handleChange}
          value={values.emailAddress}/>
      <span>{errors.emailAddress}</span>
    </td>
  </tr>
  /* Rows for organization, passwords, submit-button too!!! */ 
  </tbody>
  </table>
</form>

Использование тега tbody необходимо, потому что браузер автоматически добавит его в DOM, и React может пожаловаться, что ваш код несовместим с DOM. Однако «не» его использование «не» сломает ваше приложение из-за гибкости, встроенной в React.

Мобильные формы

Форма для мобильных устройств обычно выглядит так, как показано на рисунке. Ярлыки располагаются немного выше текстовых полей и имеют гораздо меньший размер (и полужирный шрифт).

Адаптивный дизайн будет включать как настольную, так и мобильную версии формы. Давайте посмотрим, как можно построить что-то подобное!

<form className="blackbox-form">
  <table>
  <tbody>
  <tr>
    <td className="wide-screen-label-cell">
      <label htmlFor="emailAddress">E-mail Address</label>
    </td>
    <td className="mobile-screen-label-cell">
      <label htmlFor="emailAddress">E-mail Address</label>
      <input name="emailAddress" type="text" onChange={handleChange}
          value={values.emailAddress}/>
      <span className="errors">{errors.emailAddress}</span>
    </td>
  </tr>
  </tbody>
  </table>
</form>

В нашем JSX мы включаем метки как в левый столбец, так и поверх текстового поля input. Однако наш стиль CSS отключит по крайней мере один.

.wide-screen-label-cell {
  display: none;
  text-align: right;
}
.mobile-screen-label-cell label {
  font-size: 13px;
  font-weight: bold;
}

По умолчанию (и в соответствии с принципом «сначала мобильные») наш CSS отображает только мобильную версию формы. Он скрывает ячейки столбцов с широкоэкранными метками.

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

@media only screen and (min-width: 600px) {
  .wide-screen-label-cell {
    display: block;
  }
  .mobile-screen-label-cell label {
    display: none;
  }
}

Стилизация наших ошибок также имеет решающее значение - они должны быть красными и немного меньше.

.blackbox-form .errors {// our form is classed as blackbox-form
  color: red;
  font-size: 12px;
  font-style: italics;
}

Интерактивный дизайн

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

Я надеюсь, что эта статья даст вам больше информации о формах HTML + React. Я Шукант Пал - создатель ядра Silcos.

Дальнейшее чтение: