Предыстория проблемы
Мы с вами уже познакомились с библиотекой Formik, которая значительно облегчает управление состоянием форм. Мы настроили проект, создали простую форму, обработали ввод данных и даже добавили типизацию с TypeScript. Пока всё шло гладко, но кто-то обязательно попытается ввести в поле "номер телефона" не числа, а слова типа "пятьсот двадцать". Это значит, что пора углубиться в искусство валидации данных.
Когда пользователи вводят данные в форму, нам нужно убедиться, что они валидны. Например:
- В адрес электронной почты должен быть добавлен символ
@. - Поле "пароль" должно содержать как минимум 8 символов.
- Возраст не может быть отрицательным. (Если только вы не пишете приложение для пришельцев.)
Проверять эти данные вручную — капля оптимизма в океане боли. Это муторно, баги неизбежны, а логика валидации становится громоздкой. К счастью для нас, библиотека Yup была разработана именно для этой задачи. Эта библиотека позволяет описывать правила валидации простым и понятным способом. А главное — она интегрируется с Formik, как масло с блинами.
Установка и настройка Yup
Прежде чем начать работать с Yup, нужно её установить. Yup устанавливается через npm или yarn:
npm install yup
После установки можно начинать использовать её в своём проекте.
Основы Yup: схемы валидации
В Yup всё строится на схемах валидации. Схема описывает поля формы и правила, которые применяются к этим полям. Давайте рассмотрим, как это работает.
Простой пример
Представьте, что у нас есть форма с двумя полями: name и email. Мы хотим убедиться, что:
- Поле
nameобязательно для заполнения. - Поле
emailзаполнено и имеет правильный формат.
Вот как это сделать с помощью Yup:
import * as Yup from 'yup';
const validationSchema = Yup.object({
name: Yup.string().required('Имя обязательно для заполнения'),
email: Yup.string().email('Неверный формат email').required('Email обязателен'),
});
Объяснение кода:
Yup.object()создает схему валидации для объекта.- Каждый ключ объекта схемы
nameиemailсоответствует полю формы. - Для каждого поля задаются правила:
Yup.string()— это тип поля. Оно должно быть строкой.required('...')— указывает, что поле обязательно для заполнения, с сообщением об ошибке.email('...')— проверяет, что введённое значение представляет собой корректный email.
Подключение схемы валидации к Formik
На предыдущих занятиях мы уже использовали Formik для создания форм. Теперь добавим валидацию с помощью Yup.
Пример формы с валидацией:
import React from 'react';
import { Formik, Form, Field, ErrorMessage } from 'formik';
import * as Yup from 'yup';
const validationSchema = Yup.object({
name: Yup.string().required('Имя обязательно для заполнения'),
email: Yup.string().email('Неверный формат email').required('Email обязателен'),
});
const MyForm = () => {
const initialValues = { name: '', email: '' };
const handleSubmit = (values: any) => {
console.log('Форма отправлена:', values);
};
return (
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={handleSubmit}
>
<Form>
<div>
<label htmlFor="name">Имя:</label>
<Field id="name" name="name" />
<ErrorMessage name="name" component="div" />
</div>
<div>
<label htmlFor="email">Email:</label>
<Field id="email" name="email" />
<ErrorMessage name="email" component="div" />
</div>
<button type="submit">Отправить</button>
</Form>
</Formik>
);
};
export default MyForm;
Пошаговый разбор:
- Импортируем Yup и создаём схему валидации. Эта схема проверяет, чтобы
nameбыл заполнен, аemailбыл корректным. - Передаём схему валидации в компонент Formik через проп
validationSchema. - Используем
<ErrorMessage>для отображения ошибок. Formik автоматически передаёт сообщение об ошибке из Yup.
Результат:
Если пользователь оставит поле пустым или введёт некорректный email, он увидит соответствующее сообщение об ошибке. Formik + Yup = ❤️.
Расширенные возможности Yup
Yup предоставляет множество дополнительных функций для создания правил валидации. Рассмотрим некоторые из них.
Минимальная и максимальная длина строки
const schema = Yup.object({
password: Yup.string()
.min(8, 'Пароль должен содержать минимум 8 символов')
.max(16, 'Пароль не может содержать более 16 символов')
.required('Пароль обязателен'),
});
Здесь мы используем метод min() для указания минимальной длины строки, а max() для её максимальной длины.
Проверка чисел
const schema = Yup.object({
age: Yup.number()
.min(18, 'Возраст должен быть не менее 18 лет')
.max(100, 'Возраст не может превышать 100 лет')
.required('Возраст обязателен'),
});
Методы min() и max() также работают с числами. К тому же, вы можете использовать integer() для проверки на целые числа.
Регулярные выражения
Если требуется что-то совсем кастомное, можно использовать регулярное выражение:
const schema = Yup.object({
username: Yup.string()
.matches(/^[a-zA-Z0-9_]+$/, 'Имя пользователя может содержать только буквы, цифры и нижнее подчёркивание')
.required('Имя пользователя обязательно'),
});
Метод matches() проверяет строку на соответствие регулярному выражению.
Поддержка массивов и вложенных объектов
Валидация массива значений
Если ваше поле представляет собой массив (например, список тегов или телефонов), Yup поможет и здесь:
const schema = Yup.object({
tags: Yup.array()
.of(Yup.string().required('Каждый тег должен быть строкой'))
.min(1, 'Должен быть хотя бы один тег')
.required('Массив тегов обязателен'),
});
Yup.array().of() указывает, что каждый элемент массива должен соответствовать определённой схеме.
Валидация вложенных объектов
Для сложных форм с вложенными объектами (например, адрес в форме профиля) вы можете использовать следующий подход:
const schema = Yup.object({
user: Yup.object({
name: Yup.string().required('Имя обязательно'),
email: Yup.string().email('Некорректный email').required('Email обязателен'),
}),
});
В данном случае user — это вложенный объект, каждый ключ которого имеет свои собственные правила.
Полезные мелочи: nullable() и default()
nullable()
По умолчанию Yup считает null невалидным значением. Если вы хотите допускать null как допустимое значение, используйте nullable():
const schema = Yup.object({
middleName: Yup.string().nullable().notRequired(),
});
default()
Вы можете задавать значения по умолчанию для полей:
const schema = Yup.object({
age: Yup.number().default(18),
});
В этом случае, если поле age не заполнено, оно автоматически будет равно 18.
Теперь валидация в ваших руках! Yup не только упрощает работу с правилами и ошибками, но и позволяет интегрировать строгую типизацию TypeScript. В следующей лекции мы рассмотрим, как типизировать эти правила и обрабатывать ошибки ещё более элегантно.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ