20. Form: введение
Почему TanStack Form?
Заголовок раздела «Почему TanStack Form?»Существующие библиотеки форм (React Hook Form, Formik) имеют ограничения: слабая типизация, сложная интеграция с TypeScript, отсутствие поддержки других фреймворков.
TanStack Form создан с нуля с акцентом на:
- TypeScript-first: полная типизация полей, значений и ошибок
- Фреймворк-независимость: React, Vue, Solid, Angular
- Headless: никаких встроенных UI-компонентов
- Производительность: точечные обновления, нет лишних перерендеров
Установка
Заголовок раздела «Установка»npm install @tanstack/react-formuseForm: Базовый хук
Заголовок раздела «useForm: Базовый хук»import { useForm } from '@tanstack/react-form'
const form = useForm({ defaultValues: { name: '', email: '', age: 0, }, onSubmit: async ({ value }) => { await saveUser(value) // value полностью типизирован: { name: string; email: string; age: number } },})Field API
Заголовок раздела «Field API»Поля создаются через form.Field:
<form.Field name="email" validators={{ onChange: ({ value }) => !value ? 'Обязательное поле' : !value.includes('@') ? 'Невалидный email' : undefined, onBlur: ({ value }) => value.length < 5 ? 'Слишком короткий email' : undefined, }}> {(field) => ( <div> <label>Email</label> <input name={field.name} value={field.state.value} onBlur={field.handleBlur} onChange={(e) => field.handleChange(e.target.value)} /> {field.state.meta.errors.map(error => ( <span key={error}>{error}</span> ))} </div> )}</form.Field>Field State
Заголовок раздела «Field State»field.state содержит всю информацию о поле:
field.state = { value: string, // Текущее значение meta: { errors: string[], // Массив ошибок errorMap: {...}, // Ошибки по источнику (onChange, onBlur...) isDirty: boolean, // Значение изменилось isTouched: boolean, // Пользователь взаимодействовал isValidating: boolean, // Идёт асинхронная валидация },}form.state
Заголовок раздела «form.state»Глобальное состояние формы:
form.state = { values: FormValues, // Текущие значения всех полей errors: FormErrors, // Все ошибки isSubmitting: boolean, // Форма отправляется isSubmitted: boolean, // Форма была отправлена isDirty: boolean, // Есть несохранённые изменения isValid: boolean, // Нет ошибок canSubmit: boolean, // Можно отправить}Обработка отправки
Заголовок раздела «Обработка отправки»<form onSubmit={(e) => { e.preventDefault() form.handleSubmit() }}> {/* поля */} <form.Subscribe selector={(state) => [state.canSubmit, state.isSubmitting]} > {([canSubmit, isSubmitting]) => ( <button type="submit" disabled={!canSubmit || isSubmitting}> {isSubmitting ? 'Сохранение...' : 'Сохранить'} </button> )} </form.Subscribe></form>