← Назад к вопросам

Используешь ли что-либо для работы с формами и валидацией

1.7 Middle🔥 182 комментариев
#Soft Skills и рабочие процессы

Комментарии (2)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Работа с формами и валидацией во 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.

Используешь ли что-либо для работы с формами и валидацией | PrepBro