Используешь ли что-либо для работы с формами и валидацией
Комментарии (2)
Ответ сгенерирован нейросетью и может содержать ошибки
Работа с формами и валидацией во Frontend
Да, использование специализированных инструментов для работы с формами и валидацией — это стандартная практика. Вручную обрабатывать формы неудобно, ошибко и неэффективно.
Почему нужны инструменты
Работать с формами вручную означает:
- Вручную управлять state каждого поля
- Писать свою логику валидации
- Обрабатывать ошибки и отображать их
- Сбрасывать поля при отправке
- Следить за touched/dirty состояниями
Это повторяется в каждом проекте.
Популярные библиотеки
1. React Hook Form (рекомендуемое решение)
Легкая, быстрая, с минимальным количеством ререндеров:
import { useForm } from 'react-hook-form'
export function LoginForm() {
const {
register,
handleSubmit,
formState: { errors },
reset
} = useForm({
defaultValues: { email: '', password: '' }
})
const onSubmit = async (data) => {
const response = await fetch('/api/login', {
method: 'POST',
body: JSON.stringify(data)
})
if (response.ok) {
reset()
}
}
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input
{...register('email', {
required: 'Email обязателен',
pattern: {
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
message: 'Некорректный email'
}
})}
placeholder="Email"
/>
{errors.email && <span>{errors.email.message}</span>}
<input
{...register('password', {
required: 'Пароль обязателен',
minLength: {
value: 6,
message: 'Минимум 6 символов'
}
})}
type="password"
placeholder="Пароль"
/>
{errors.password && <span>{errors.password.message}</span>}
<button type="submit">Войти</button>
</form>
)
}
Преимущества:
- Минимум ререндеров (использует uncontrolled компоненты)
- Маленький bundle size
- Отличная производительность
- Хороший TypeScript support
2. Formik (классический вариант)
Больше features, но тяжелее:
import { Formik, Form, Field, ErrorMessage } from 'formik'
import * as Yup from 'yup'
const validationSchema = Yup.object().shape({
email: Yup.string()
.email('Некорректный email')
.required('Email обязателен'),
password: Yup.string()
.min(6, 'Минимум 6 символов')
.required('Пароль обязателен')
})
export function LoginForm() {
return (
<Formik
initialValues={{ email: '', password: '' }}
validationSchema={validationSchema}
onSubmit={(values) => {
console.log(values)
}}
>
{({ isSubmitting }) => (
<Form>
<Field
name="email"
type="email"
placeholder="Email"
/>
<ErrorMessage name="email" />
<Field
name="password"
type="password"
placeholder="Пароль"
/>
<ErrorMessage name="password" />
<button type="submit" disabled={isSubmitting}>
Войти
</button>
</Form>
)}
</Formik>
)
}
Преимущества:
- Много встроенных features
- Хороший dev experience
- Экосистема интеграций
Недостатки:
- Больше ререндеров
- Больший bundle size
- Сложнее с performance на больших формах
3. Zod для валидации (отдельно)
Мощная библиотека для валидации с TypeScript:
import { z } from 'zod'
const loginSchema = z.object({
email: z.string().email('Некорректный email'),
password: z.string().min(6, 'Минимум 6 символов'),
rememberMe: z.boolean().optional()
})
type LoginFormData = z.infer<typeof loginSchema>
const handleSubmit = async (data: LoginFormData) => {
const result = loginSchema.safeParse(data)
if (!result.success) {
console.log(result.error.errors)
return
}
// Отправить на сервер
}
Встроенная валидация HTML5
Для простых случаев можно использовать встроенную валидацию:
<input
type="email"
required
placeholder="Email"
/>
<input
type="password"
required
minlength="6"
placeholder="Пароль"
/>
<input
type="text"
pattern="[0-9]{10}"
placeholder="Телефон"
/>
Однако это не заменяет серверную валидацию!
Серверная валидация
ВАЖНО: Всегда валидируй данные на сервере!
// Frontend валидация — для UX
// Backend валидация — для безопасности
const handleSubmit = async (data) => {
// Frontend валидация (для пользователя)
const frontendValidation = loginSchema.safeParse(data)
if (!frontendValidation.success) {
showErrors(frontendValidation.error.errors)
return
}
// Отправляем на backend
const response = await fetch('/api/login', {
method: 'POST',
body: JSON.stringify(data)
})
// Backend может вернуть свои ошибки
if (!response.ok) {
const { errors } = await response.json()
showErrors(errors)
return
}
// Успешно
redirectToHome()
}
Custom валидация
Иногда нужна своя логика:
const registerSchema = z.object({
email: z.string().email(),
password: z.string().min(8),
confirmPassword: z.string()
}).refine((data) => data.password === data.confirmPassword, {
message: 'Пароли не совпадают',
path: ['confirmPassword']
}).refine(async (data) => {
// Проверить, есть ли уже такой email
const response = await fetch(`/api/check-email?email=${data.email}`)
return response.ok
}, {
message: 'Этот email уже зарегистрирован',
path: ['email']
})
Best Practices
1. Отделяй валидацию от компонента
// schemas/auth.ts
export const loginSchema = z.object({
email: z.string().email(),
password: z.string().min(6)
})
// components/LoginForm.tsx
import { loginSchema } from '@/schemas/auth'
2. Используй TypeScript для типизации
type LoginData = z.infer<typeof loginSchema>
3. Показывай валидацию в real-time
<input
{...register('email')}
onBlur={() => trigger('email')} // Триггер валидацию
/>
4. Обрабатывай асинхронную валидацию
const { register } = useForm({
resolver: zodResolver(schema),
mode: 'onBlur' // Валидируй при потере фокуса
})
Моя рекомендация
Для большинства проектов:
- React Hook Form + Zod — идеальная комбинация
- Минимум кода
- Отличная производительность
- Хороший TypeScript support
- Легко расширяемо
import { useForm } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import { z } from 'zod'
const schema = z.object({
email: z.string().email(),
password: z.string().min(6)
})
export function LoginForm() {
const { register, handleSubmit, formState: { errors } } = useForm({
resolver: zodResolver(schema)
})
return (
<form onSubmit={handleSubmit(onSubmit)}>
{/* ... */}
</form>
)
}
Итог: Используй проверенные библиотеки для форм вместо ручной реализации. Это экономит время, улучшает quality и дает лучший UX.