Создание лучших форм 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 неинтересно; это очень многословно и жестко. Построение формы и создание метода проверки — скучные задачи. В каждой форме вам нужно будет сделать как минимум следующее:
- Настройка состояния для значений формы, ошибок формы и действительности формы
- Обработка пользовательского ввода и обновление состояния
- Создание функций проверки
- Обработка представления
Создание форм естественным способом «React» требует, чтобы вы написали каждую часть процесса от настройки состояний до отправки формы. Я сделал бесчисленное количество форм React, и я всегда нахожу эту часть создания форм очень скучной и трудоемкой. К счастью, я не единственный, кто так себя чувствует.
Введите Формик
Джаред Палмер создал библиотеку Formik из-за разочарования при создании форм React. Ему нужен был способ стандартизировать компоненты ввода и процесс отправки форм. 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 />
составная часть:
С валидатором схемы объектов 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 уже сегодня!
Первоначально опубликовано 28 июня 2019 г.