React / Forms / Next.js

    Formularze w React 2024

    TanStack Form (type-safe), React Hook Form v7, Server Actions + useActionState, Zod walidacja i Next.js 15 formularze.

    TanStack Form
    Type-safe
    React HF
    Dojrzały
    Server Actions
    No-JS
    Zod
    Walidacja

    6 bibliotek formularzy React — porównanie

    TanStack Form, React Hook Form, Server Actions, Zod, Formik i useOptimistic — typ i kiedy wybrać.

    Biblioteka Typ Kiedy
    TanStack Form Headless, framework-agnostic Nowe projekty, multi-framework, type-safe-first
    React Hook Form v7 React, uncontrolled DOM Produkcja, dojrzały, shadcn/ui integration
    Server Actions + useActionState Next.js 15, RSC Progressive enhancement, brak JS fallback
    Zod validation Schema validation Walidacja klient i serwer — jeden schemat
    Formik React (stary standard) Legacy kod — consider migracja do RHF
    useOptimistic React 19, optimistic UI Natychmiastowy feedback, rollback przy błędzie

    Często zadawane pytania

    TanStack Form — co to jest i jak różni się od React Hook Form?

    TanStack Form: framework-agnostic form management. TypeScript-first. Zero dependencies. Headless (brak UI). Wersja: v0 (eksperymentalna), stabilizująca się. Instalacja: npm install @tanstack/react-form. Podstawy: import {useForm} from '@tanstack/react-form'. const form = useForm({defaultValues: {name: '', email: '', age: 0}, onSubmit: async ({value}) => { console.log(value) }}). Pola: form.Field — komponent dla pola. api.field.handleChange, api.field.state.value, api.field.state.meta. Składnia: form.Field({name: 'name', children: (field) => input({value: field.state.value, onChange: (e) => field.handleChange(e.target.value)})}). TypeScript: pełna inferencja typów. value typowany z defaultValues. errors typowane. Validatory. Porównanie z React Hook Form: RHF — register/Controller/useFormContext. TanStack Form — Field component. RHF — uncontrolled domyślnie. TanStack Form — controlled. RHF — dojrzalszy (v7, duża społeczność). TanStack Form — nowoczesny DX, type-safe. RHF — Zod integration @hookform/resolvers. TanStack Form — wbudowane validators. Framework: RHF — React only. TanStack Form — React, Vue, Angular, Solid, Lit. Formik: stary, wolniejszy, mniejszy DX. Kiedy TanStack Form: nowe projekty chcące type-safe. Nie-React framework (Vue, Solid). Multi-framework (design system).

    TanStack Form — walidacja pól i integracja z Zod?

    Wbudowana walidacja: validators prop na Field. validators: {onChange: ({value}) => !value ? 'Required' : undefined}. Zwróć string = błąd. undefined = ok. Kiedy walidować: onChange — przy zmianie. onBlur — po opuszczeniu. onSubmit — przy submitcie. onChangeAsyncDebounceMs — async z debounce. Async walidacja: validators: {onChangeAsync: async ({value}) => { const taken = await checkEmail(value). return taken ? 'Email zajęty' : undefined }, onChangeAsyncDebounceMs: 500}. Zod integration: npm install @tanstack/zod-form-adapter. import {zodValidator} from '@tanstack/zod-form-adapter'. const form = useForm({validatorAdapter: zodValidator(), defaultValues: {name: ''}. validators: {onSubmit: z.object({name: z.string().min(2)})}}). Field-level Zod: form.Field({name: 'email', validatorAdapter: zodValidator(), validators: {onChange: z.string().email()}}). Błędy: field.state.meta.errors — tablica stringów. field.state.meta.isValidating — async w toku. field.state.meta.isTouched — było dotykane. form.state.isValid — cały formularz. form.state.errors — wszystkie błędy. Formularz walidacja: form level validators. validators: {onSubmit: ({value}) => { if (!value.name || !value.email) return {fields: {name: 'Required'}} }}. Linki między polami: confirm password. field zmienia inny field. form.setFieldValue('confirmPassword', ''). Cross-field walidacja.

    TanStack Form — zaawansowane wzorce: array fields i sub-forms?

    Array Fields: dla dynamicznych list. form.Field({name: 'friends', mode: 'array', children: (field) => { field.state.value.map((_, i) => form.Field({name: 'friends[i].name', children: (subField) => input({...}) })) } }). Push: field.pushValue({name: '', age: 0}). Remove: field.removeValue(i). Swap: field.swapValues(i, j). Insert: field.insertValue(i, value). Nested Objects: name: 'address.street'. Automatyczna praca zagnieżdżeń. type-safe dzięki TypeScript. Conditional fields: watch: field.state.value — nie ma reaktywnego watcha. useStore(form.store, (s) => s.values.type) — subskrybuj. Renderuj warunkowo. Sub-forms: compose form z sub-komponenty. Przekaż form.Field jako props. Reużywalne sekcje formularza. useField hook: const field = useField({name: 'email', form}). Imperativo dostęp do pola. Poza Field komponentem. Reset: form.reset() — resetuj do defaultValues. form.setFieldValue('name', newValue). form.setValues({...}). Dirty state: form.state.isDirty — czy zmieniono. field.state.meta.isDirty — per field. Prevent navigate when dirty. Optimistic updates: submit -> update UI od razu. Rollback przy błędzie. Server-side validation errors: form.setFieldMeta('email', (prev) => ({...prev, errors: ['Email zajęty']})). Lub setErrors. Obsługa server błędów. Accessibility: label htmlFor powiązany z input. aria-describedby dla błędów. aria-invalid na błędnych polach. role='alert' dla błędów.

    React Hook Form v7 — najlepsze praktyki i zaawansowane wzorce?

    React Hook Form: najdojrzalszy form library. register() — uncontrolled. Controller — dla kontrolowanych komponentów. useFormContext — formularz w drzewie. useWatch — reaktywne watch. useFieldArray — array fields. Optymalizacja: register() nie powoduje re-renderu. watch() powoduje — używaj ostrożnie. useWatch() dla lokalnego watcha. shouldUnregister: false — zachowaj wartości po odmontowaniu. Schema validation: yupResolver, zodResolver, joiResolver. @hookform/resolvers. const schema = z.object({...}). resolver: zodResolver(schema). Formstate: isDirty, isSubmitting, isValid, errors, dirtyFields, touchedFields, isValidating. useFormState — lokalny dostęp. FormProvider: context dla zagnieżdżeń. useFormContext — dostęp w potomkach. Bez prop drilling. DevTools: @hookform/devtools. Podgląd state. Błędy. Re-renders count. Array Fields: useFieldArray({control, name: 'items'}). append, prepend, remove, update, swap, insert. key z id (nie index). Trigger validation: trigger('email') — waliduj konkretne pole. trigger() — wszystkie. Conditional: watch('type') === 'business' ? showCompanyField. setError: setError('server', {type: 'manual', message: 'Server error'}). clearErrors: clearErrors('field'). Controlled z shadcn/ui: Controller - render - FormField. Standardowy pattern.

    Formularze w Next.js — Server Actions, useActionState i progressive enhancement?

    Server Actions + formularz: form action={serverAction}. Bez JavaScript! Progressive enhancement. Działa bez JS (basic form). Z JS: szybki submit bez przeładowania. Server Action: 'use server'. export async function createUser(formData: FormData) { const name = formData.get('name') as string. const email = formData.get('email') as string. await db.user.create({data: {name, email}}) }. useActionState (React 19): const [state, action, isPending] = useActionState(serverAction, null). form action={action}. state — wynik poprzedniego wywołania. isPending — czy w trakcie. Walidacja serwer-side: Zod w Server Action. schema.safeParse(Object.fromEntries(formData)). Zwróć błędy w state. return {errors: {email: 'Invalid email'}}. Wyświetl w kliencie: state.errors.email. useOptimistic: optymistyczne update UI. Przed odpowiedzią serwera. Rollback przy błędzie. TanStack Form + Server Actions: action prop na form. handleSubmit -> Server Action. React Hook Form + Server Actions: handleSubmit(async (data) => { await serverAction(data) }). Albo: startTransition(() => { form.action(new FormData(...)) }). useFormStatus: const {pending} = useFormStatus(). W submit button. Spinners podczas submit. Działa z form action. File uploads: FormData + Server Action. multipart/form-data. Walidacja pliku. Streaming feedback: readableStream z Server Action. useFormState + streaming. Pasek postępu upload. Bezpieczeństwo: CSRF automatyczny (Next.js). Waliduj serwer-side zawsze. Rate limiting na Server Actions.

    Czytaj dalej

    Powiązane artykuły

    Kontakt

    Skontaktuj się z nami

    Porozmawiajmy o Twoim projekcie. Bezpłatna wycena w ciągu 24 godzin.

    Wyślij zapytanie

    Bezpłatna wycena w 24h
    Bez zobowiązań
    Indywidualne podejście
    Ekspresowa realizacja

    Telefon

    +48 790 814 814

    Pon-Pt: 9:00 - 18:00

    Email

    adam@fotz.pl

    Odpowiadamy w ciągu 24h

    Adres

    Plac Wolności 16

    61-739 Poznań

    Godziny pracy

    Pon - Pt9:00 - 18:00
    Sob - NdzZamknięte

    Wolisz porozmawiać?

    Zadzwoń teraz i porozmawiaj z naszym specjalistą o Twoim projekcie.

    Zadzwoń teraz