React / Forms

    React Hook Form i Zod

    Walidacja formularzy z React Hook Form, Zod schema validation, zodResolver i integracja z Next.js Server Actions.

    RHF
    Minimum re-renders
    Zod
    Schema + TypeScript
    zodResolver
    Bridge RHF+Zod
    useFieldArray
    Dynamiczne pola

    6 bibliotek formularzy i walidacji

    React Hook Form, Formik, TanStack Form, Zod, Valibot i TypeBox — porównanie re-renderów, rozmiaru i podejścia do walidacji.

    Biblioteka Rozmiar Re-rendery Walidacja Kiedy
    React Hook Form 9KB Minimalne (uncontrolled) Resolver pattern Standard — używaj domyślnie
    Formik 15KB Każdy keystroke (controlled) validate / Yup schema Legacy projekty, Yup preference
    TanStack Form 7KB Fine-grained reactive Adapter pattern Framework-agnostic, eksperymentalny
    Final Form 5KB Subscription-based Ręczna / adapter Complex dependencies, pub-sub
    Zod (schema) 8KB N/A (walidacja) Runtime + TypeScript types Standard do walidacji w RHF
    Valibot (schema) 1KB+ N/A (walidacja) Modular, tree-shakeable Bundle-size critical apps

    Często zadawane pytania

    Co to jest React Hook Form i dlaczego jest lepszy od Formik?

    React Hook Form (RHF): biblioteka formularzy dla React (Bluebill1049, 2019). Filozofia: uncontrolled inputs z register(). Minimalny re-render. Bez Provider. Podstawowe użycie: const {register, handleSubmit, formState: {errors}} = useForm(). input {...register('email', {required: true, pattern: EMAIL_REGEX})}. handleSubmit(data => console.log(data)). Dlaczego lepszy od Formik: Formik: controlled inputs -> re-render przy każdym keystroke. RHF: ref-based -> re-render tylko przy submit/błędzie. Bundle size: RHF 9KB vs Formik 15KB. Performance: RHF zdecydowanie szybszy dla dużych formularzy. API: RHF prostszy (register pattern). Formik: values, touched, handleChange — verbose. TypeScript: RHF natywny TS support. Formik: mniej friendly. RHF zaawansowane: useController — controlled component API. Controller component — dla UI library (shadcn/ui, MUI). useFieldArray — dynamiczne listy. watch() — obserwuj pola. setValue / getValues / reset. trigger() — manualna walidacja. useFormContext — dostęp przez Context w zagnieżdżonych komponentach. FormProvider — provider dla useFormContext. Mode: onChange/onBlur/onSubmit/all — kiedy walidować. shouldFocusError — focus na pierwszym błędzie. Resolver — zewnętrzna walidacja (Zod, Yup, Joi). RHF + shadcn/ui: Form, FormField, FormItem, FormLabel, FormControl, FormMessage — wbudowana integracja.

    Zod — runtime schema validation i TypeScript type inference?

    Zod: schema-first TypeScript validation library (Colin McDonnell, 2020). Type-safe: schema generuje TypeScript typy. Runtime validation: walidacja danych wejściowych w runtime. Zero dependencies. 8KB gzipped. Podstawy: z.string(), z.number(), z.boolean(), z.date(). z.string().min(3).max(50).email(). z.number().int().positive().min(0).max(100). z.object({name: z.string(), age: z.number()}). Type inference: const UserSchema = z.object({...}). type User = z.infer typeof UserSchema. Zaawansowane typy: z.union([z.string(), z.number()]). z.discriminatedUnion('type', [...]). z.array(z.string()).min(1). z.tuple([z.string(), z.number()]). z.record(z.string(), z.number()). z.enum(['a', 'b', 'c']). z.literal('admin'). z.optional(z.string()) = z.string().optional(). z.nullable(z.string()). z.default('default value'). Transformacje: z.string().transform(val => parseInt(val)). z.preprocess(val => String(val), z.string()). Custom validation: z.string().refine(val => val.includes('@'), 'Must contain @'). z.object({...}).superRefine((data, ctx) => {if (data.password !== data.confirm) ctx.addIssue(...)})). Error handling: schema.safeParse(data) — nie rzuca. result.success, result.data, result.error. schema.parse(data) — rzuca ZodError. z.ZodError.flatten() — flat error map. Zod vs Yup: Zod — TypeScript native, tree-shakeable, szybszy. Yup — starszy, async-first, addMethod dla extensji. Joi — server-side, Node.js, brak TS inference.

    React Hook Form + Zod resolver — kompletna integracja?

    @hookform/resolvers: bridge między RHF a bibliotekami walidacji. zodResolver, yupResolver, joiResolver. import {zodResolver} from '@hookform/resolvers/zod'. const schema = z.object({email: z.string().email('Invalid email'), password: z.string().min(8, 'Min 8 chars'), age: z.number().min(18, 'Must be 18+')}). type FormData = z.infer typeof schema. const {register, handleSubmit, formState: {errors}} = useForm FormData ({resolver: zodResolver(schema), defaultValues: {email: '', age: 18}}). errors.email?.message — z Zod error messages. Złożone formularze: useFieldArray — dynamiczne pola. const {fields, append, remove, move} = useFieldArray({control, name: 'items'}). fields.map((field, i) => input {...register('items.${i}.name')}). MultiStep forms: FormProvider + useFormContext. Każdy step = osobny komponent. Shared form state przez Context. trigger(['field1', 'field2']) — waliduj tylko dany step. Conditional fields: watch('type') — obserwuj pole. Warunkowa rejestracja innych pól. useWatch — zoptymalizowany, bez re-render parenta. Async walidacja: z.string().refine(async email => checkEmailExists(email), 'Email taken'). mode: 'onBlur' dla async. Server errors: setError('email', {message: 'Already taken'}). clearErrors() po poprawce. Performance tips: defaultValues — zawsze podawaj. useFormContext zamiast prop drilling. formState.isSubmitting — loading state. reset() po sukcesie. resetField() dla konkretnego pola.

    Walidacja po stronie serwera — Zod w Next.js Server Actions i API routes?

    Zod na serwerze: walidacja danych wejściowych przed przetwarzaniem. Server Actions (Next.js): 'use server'. const schema = z.object({name: z.string().min(1), email: z.string().email()}). async function createUser(formData: FormData) {'use server'. const raw = {name: formData.get('name'), email: formData.get('email')}. const parsed = schema.safeParse(raw). if (!parsed.success) return {errors: parsed.error.flatten().fieldErrors}. prisma.user.create({data: parsed.data})}. API Routes (Next.js): const body = await req.json(). const result = schema.safeParse(body). if (!result.success) return Response.json({errors: result.error.flatten()}, {status: 422}). Middleware validation: Zod w middleware.ts dla route-level. Shared schemas: schemas/ katalog. Importowane przez client i server. Unikaj duplikacji. Toto ze środowiskiem: env schema. z.object({DATABASE_URL: z.string().url(), NODE_ENV: z.enum(['development', 'production', 'test'])}). createEnv (@t3-oss/env-nextjs): bezpieczne zmienne środowiskowe. Zod z tRPC: input: z.object({...}) jako procedura input. Automatyczna walidacja. Type-safe client i server. Zod z Prisma: zod-prisma-types — generuj Zod schemas z Prisma schema. prisma-zod-generator. Eliminuje ręczne pisanie schemas.

    Alternatywne biblioteki — Valibot, Effect Schema, TypeBox i arktype?

    Landscape bibliotek walidacji 2024: Zod: standard, ogromna adopcja, 8KB. Valibot: modular (tylko to co używasz), tree-shakeable, 1KB+. Prawie identyczne API co Zod. Szybszy. Effect Schema: część Effect ekosystemu (functional TypeScript). Bardzo potężny, ale złożony. TypeBox: JSON Schema + TypeScript. Generuje JSON Schema i typy jednocześnie. Używany w Fastify (TypeBox + Fastify = zero overhead). Arktype: holistyczny, runtime types, operator syntax. const User = type({name: 'string', age: 'number>0'}). Najbardziej ekspresywny syntax. Runtypes: functional style. Jak wybrać: Zod — standard, next-intl, tRPC, RHF. Valibot — bundle size krytyczny. TypeBox — Fastify API. Arktype — nowoczesny syntax. t3-oss/env: typesafe env vars. z.object({}) dla server + client envs. Valibot przykład: import {email, minLength, object, string, parse} from 'valibot'. const Schema = object({email: string([email()]), password: string([minLength(8)])}). Identyczne jak Zod ale tree-shakeable. SuperJSON: serialization (Date, Map, Set, undefined). Używany przez tRPC. Zod + SuperJSON = kompletne rozwiązanie. Konkluzja: Zod to de facto standard 2024. Valibot rosnąca popularność. TypeBox dla performance-critical API.

    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