IlmHamroh
JavaScript Full-stack/19-qism. React: routing, server state, formalar34/36-dars19 daqiqa
Mundarija (28)

Forma va validatsiya kutubxonalari: Formik, TanStack Form, Conform, Valibot va Standard Schema

Qisqacha: Forma kutubxonasi (qiymat, xato, yuborish holati) va sxema kutubxonasi (qoidalar) — ikki alohida tanlov. Ularni Standard Schema — sxemalarning umumiy interfeysi (schema["~standard"].validate) — bog'laydi: Zod, Valibot, ArkType bir xil "rozetka"ga ulanadi. Bizning o'lchovda bitta formaning narxi (React bilan, gzip): kutubxonasiz <form action> 72.2 KB, RHF 84.6, Formik 84.2, TanStack Form 88.3, Conform 93.7. Sxema: Zod 23.7 KB, zod/mini 5.8, Valibot 1.6. Eng yaxshisi yo'q — vaziyatga mosi bor.

Bu darsda

  • Bitta formani besh xil (React'ning o'zi, RHF, Formik, TanStack Form, Conform) o'qiysiz va farqini tushuntira olasiz.
  • Har kutubxonaning hajmini haqiqiy o'lchov bilan solishtirasiz.
  • Standard Schema nima ekanini ko'rasiz va unga ulanadigan o'z resolveringizni yozasiz.
  • Valibot, ArkType va Yup ni Zod bilan solishtirasiz va qaysi vaziyatda qaysi biri to'g'ri tanlov ekanini aytasiz.

Oldin bilishingiz kerak: RHF III, RHF + Zod: resolver, Zod va turni sxemadan chiqarish, useActionState va useFormStatus.

1. Nega bu kerak?

To'rt darsda React Hook Form va Zod bilan ishladik. Sardor ishga kirgan kompaniyada esa boshqa narsa: eski admin panel Formik va Yup da, yangi Next.js loyiha Conform da, yaqinda qo'shilgan jamoa TanStack Form ni taklif qilyapti. U birinchi kunidan bu kodni o'qishi va "nega aynan shu?" degan savolga javob berishi kerak.

Bu dars "eng yaxshi kutubxona" ni topmaydi. U har birining qaysi muammoni hal qilishini va narxini ko'rsatadi. Hayotiy o'xshatish: transport. Toshkent ichida metro tez, qishloqqa esa mashina kerak, og'ir yuk uchun — yuk mashinasi. "Eng yaxshi transport" yo'q, "bu yo'lga mosi" bor.

Avval ikki tanlovni ajratib olaylik:

Tanlov Nima qiladi Variantlar
forma kutubxonasi qiymatlar, xatolar, isSubmitting, isDirty, dinamik maydonlar React'ning o'zi, RHF, Formik, TanStack Form, Conform
sxema kutubxonasi qoidalar, tur chiqarish, transform Zod, zod/mini, Valibot, ArkType, Yup

Ular mustaqil: RHF Valibot bilan ham, TanStack Form Zod bilan ham ishlaydi. Bog'lovchi — resolver yoki Standard Schema («Standard Schema — umumiy rozetka» bo'limida).

2. Bitta forma — besh xil

2.1 Tajriba

vazifalar uchun forma tanlashdan oldin biz bitta kichik vazifani besh usulda yozdik: matn (majburiy, chetlari kesiladi, ≤ 100 belgi) va "bajarildi" katagi. Sxema hammasida bir xil — zod/mini (Zod chuqurroq). Har variant alohida Vite build qilindi va hajmi o'lchandi (gzip -9), turlari tsc bilan tekshirildi. Fayllar — kanondagi sinov/19/tajriba/variantlar/ (kanonga kirmagan tajriba).

Bu kutubxonalar saytdagi natija oynasida yo'q — quyidagi bloklar «Ishga tushir» siz, kanon tajribasidan aynan. O'z loyihangizda npm install bilan sinab ko'rishingiz mumkin (versiyalar pastdagi jadvalda).

Umumiy sxema (kanon, _forma.ts):

ts
import { z } from "zod/mini";

export const formaSxemasi = z.object({
  matn: z.string().check(
    z.trim(),
    z.minLength(1, "Vazifa matnini yozing."),
    z.maxLength(100, "Matn juda uzun."),
  ),
  bajarildi: z.boolean(),
});
export type FormaQiymati = z.output<typeof formaSxemasi>;

Tajriba fayllarida ko'p narsa bir qatorga yozilgan (ular o'lchov uchun). Bu yerda ular telefonga sig'ishi uchun qatorlarga bo'lingan — kodning o'zi o'zgarmagan.

2.2 React'ning o'zi: <form action>

Kutubxonasiz — useActionState bilan (kanon, forma-native.tsx):

tsx
function Forma() {
  const [holat, action] = useActionState(
    (_: { xato: string | null; matn: string }, f: FormData) => {
      const n = formaSxemasi.safeParse({
        matn: String(f.get("matn") ?? ""),
        bajarildi: f.get("bajarildi") === "on",
      });
      if (!n.success)
        return {
          xato: n.error.issues[0]?.message ?? null,
          matn: String(f.get("matn") ?? ""),
        };
      yubor(n.data);
      return { xato: null, matn: "" };
    },
    { xato: null, matn: "" },
  );
  return (
    <form noValidate action={action}>
      <input
        aria-label="Matn"
        name="matn"
        defaultValue={holat.matn}
      />
      <p>{holat.xato}</p>
      <input
        type="checkbox"
        aria-label="Bajarildi"
        name="bajarildi"
      />
      <button>Saqlash</button>
    </form>
  );
}

FormData dan qiymatlar qo'lda olinadi, checkbox — "on" yoki yo'q (Zod chuqurroq dagi jadval). Xato — bitta umumiy. defaultValue={holat.matn} — action'dan keyin matn yo'qolmasin (Formalar II). Bu — vazifalar dagi tezkor formaning yo'li.

2.3 React Hook Form

Kanon, forma-rhf.tsx:

tsx
function Forma() {
  const { register, handleSubmit, formState } = useForm({
    resolver: zodResolver(formaSxemasi),
    defaultValues: { matn: "", bajarildi: false },
  });
  return (
    <form noValidate onSubmit={(e) => void handleSubmit(yubor)(e)}>
      <input aria-label="Matn" {...register("matn")} />
      <p>{formState.errors.matn?.message}</p>
      <input
        type="checkbox"
        aria-label="Bajarildi"
        {...register("bajarildi")}
      />
      <button>Saqlash</button>
    </form>
  );
}

Tanish: uncontrolled maydonlar, register, resolver (RHF I – RHF III).

2.4 Formik

Formik (2.4.9) — RHF dan oldingi davrning eng mashhur forma kutubxonasi. Bugun u "eski" (legacy) hisoblanadi: yangi loyihada kam tanlanadi, lekin eski kodda juda ko'p uchraydi. Kanon, forma-formik.tsx:

tsx
function Forma() {
  return (
    <Formik
      initialValues={{ matn: "", bajarildi: false }}
      validate={(q) => {
        const n = formaSxemasi.safeParse(q);
        return n.success
          ? {}
          : Object.fromEntries(
              n.error.issues.map((i) => [String(i.path[0]), i.message]),
            );
      }}
      onSubmit={(q) => yubor(formaSxemasi.parse(q))}
    >
      {({ errors }) => (
        <Form noValidate>
          <Field name="matn" aria-label="Matn" />
          <p>{errors.matn}</p>
          <Field
            type="checkbox"
            name="bajarildi"
            aria-label="Bajarildi"
          />
          <button type="submit">Saqlash</button>
        </Form>
      )}
    </Formik>
  );
}

Farqlar:

  • Controlled. Formik qiymatlarni o'z state'ida saqlaydi — har harfda forma qayta chiziladi. RHF ning "uncontrolled" yo'li aynan shu muammoga javob sifatida paydo bo'lgan.
  • Render prop — {({ errors }) => …} (render props). Hook'lar davridan oldingi naqsh; Formik'da useFormik hook'i ham bor.
  • validate — Zod resolveri o'rniga, xatolarni o'zimiz { maydon: xabar } ga aylantirdik (shu blokdagi Object.fromEntries). Formik'ning "o'z" sxema kutubxonasi — Yup (validationSchema).

Qachon to'g'ri tanlov: mavjud Formik loyihasi. Ishlab turgan formani ko'chirish — RHF I dagi "ko'chirmaslik" qarori bilan bir xil savol: foyda xavfdan kattami?

2.5 TanStack Form

TanStack Form (1.33.5) — TanStack Query va Router mualliflarining forma kutubxonasi. Asosiy g'oyasi — turlar: maydon nomi, qiymati va xatosi butunlay type-safe. Kanon, forma-tanstack.tsx:

tsx
function Forma() {
  const forma = useForm({
    defaultValues: { matn: "", bajarildi: false },
    validators: { onSubmit: formaSxemasi },
    onSubmit: ({ value }) => yubor(formaSxemasi.parse(value)),
  });
  return (
    <form
      noValidate
      onSubmit={(e) => {
        e.preventDefault();
        void forma.handleSubmit();
      }}
    >
      <forma.Field name="matn">
        {(f) => (
          <>
            <input
              aria-label="Matn"
              value={f.state.value}
              onChange={(e) => f.handleChange(e.target.value)}
              onBlur={f.handleBlur}
            />
            <p>
              {f.state.meta.errors.map((x) => x?.message).join(", ")}
            </p>
          </>
        )}
      </forma.Field>
      <forma.Field name="bajarildi">
        {(f) => (
          <input
            type="checkbox"
            aria-label="Bajarildi"
            checked={f.state.value}
            onChange={(e) => f.handleChange(e.target.checked)}
          />
        )}
      </forma.Field>
      <button>Saqlash</button>
    </form>
  );
}

E'tibor bering: validators: { onSubmit: formaSxemasi } — sxema to'g'ridan berildi, resolver yo'q. TanStack Form Standard Schema'ni o'zi tushunadi (pastda, «Standard Schema» bo'limida). Har maydon — forma.Field komponenti, ichida controlled <input> (qiymat va handleChange qo'lda ulanadi). Kod uzunroq, lekin name="matnn" deb xato yozsangiz — tsc darhol ushlaydi.

Qachon to'g'ri tanlov: TypeScript'ga qattiq tayanadigan jamoa, murakkab formalar, TanStack ekotizimi (Query, Router, Table) allaqachon ishlatilgan loyiha.

2.6 Conform

Conform (1.21.1) — server action'lar uchun yaratilgan. Asosiy g'oyasi — progressiv yaxshilash (progressive enhancement): forma JavaScript yuklanmasa ham ishlaydi (oddiy HTML forma bo'lib yuboriladi), JavaScript bilan esa jonli xatolar qo'shiladi. Kanon, forma-conform.tsx:

tsx
function Forma() {
  const [forma, maydonlar] = useForm({
    onValidate: ({ formData }) =>
      parseWithZod(formData, { schema: formaSxemasi }),
    onSubmit: (e, { submission }) => {
      e.preventDefault();
      if (submission?.status === "success") yubor(submission.value);
    },
  });
  return (
    <form id={forma.id} noValidate onSubmit={forma.onSubmit}>
      <input aria-label="Matn" name={maydonlar.matn.name} />
      <p>{maydonlar.matn.errors}</p>
      <input
        type="checkbox"
        aria-label="Bajarildi"
        name={maydonlar.bajarildi.name}
      />
      <button>Saqlash</button>
    </form>
  );
}

parseWithZod(formData, …) — FormData ni sxemaga moslab o'giradi (checkbox "on" → true, bo'sh satr → undefined) va tekshiradi. Xuddi shu funksiya serverda ham ishlaydi: Next.js server action (Server Actions I) formani oladi, parseWithZod qiladi, xato bo'lsa — qaytaradi, Conform uni maydonlar ostiga qo'yadi.

Qachon to'g'ri tanlov: Next.js / Remix server action'lari, JavaScript'siz ham ishlashi muhim bo'lgan formalar (sekin internet, eski telefon).

Tekshirib ko'ring: "Sekin internetda sahifa ochildi, JavaScript hali yuklanmadi, mehmon «Yuborish» ni bosdi." Qaysi variantlar ishlaydi?

Javob

React'ning <form action> (server action bilan, Next.js'da) va Conform — ular oddiy HTML forma sifatida yuboriladi va server javob beradi. RHF, Formik, TanStack Form esa onSubmit hodisasiga tayanadi: JavaScript yo'q — hodisa ham yo'q, brauzer formani action siz joriy sahifaga yuboradi (yoki hech narsa bo'lmaydi). Bizning SPA (vazifalar) da bu farq yo'q: JavaScript'siz ilovaning o'zi yo'q.

3. Narxi: o'lchov

3.1 Forma kutubxonalari

Hamma variant — bir xil React 19.3.0 va zod/mini sxemasi bilan. Raqam — brauzer yuklaydigan butun JavaScript (gzip -9). Kanon natijalar/tajriba/hajm.txt dan (Node 24.21.0, Vite 8.3.3):

text
variant                    xom B   gzip B  qator
forma-conform             306960    93744     22
forma-formik              272271    84163     25
forma-native              233664    72242     20
forma-rhf                 268141    84597     19
forma-tanstack            299038    88270     33
Bitta forma: React + kutubxona + zod/mini (gzip)
  • <form action> (kutubxonasiz)72,2 KB
  • Formik 2.4.984,2 KB
  • React Hook Form 7.89.084,6 KB
  • TanStack Form 1.33.588,3 KB
  • Conform 1.21.193,7 KB

Manba: O'lchandi: sinov/19/tajriba (Vite 8.3.3, gzip -9), natijalar/tajriba/hajm.txt, 2026-10-13

Kutubxonasiz variantga nisbatan qo'shimcha:

Kutubxona + KB (gzip) Manba qatori
Formik +11.9 25
React Hook Form (+ resolvers) +12.4 19
TanStack Form +16.0 33
Conform (+ @conform-to/zod) +21.5 22

Uch xulosa:

  1. Farqlar kichik — 12–22 KB. Bu bitta o'rtacha rasmdan kam. Kutubxona tanlovini hajm emas, qulaylik va jamoa hal qiladi.
  2. Kutubxonasiz eng kichik — lekin unda isDirty, maydon xatolari, dinamik ro'yxat yo'q. Ularni qo'lda yozsangiz, kod ham, hajm ham o'sadi.
  3. Qator soni — taxminiy "qulaylik" o'lchovi: RHF eng qisqa (19), TanStack Form eng uzun (33) — type-safe'lik uchun maydonlar aniq ulanadi.

Bu o'lchov hajm va turlar haqida: variantlar build qilindi va tsc dan xatosiz o'tdi (natijalar/tajriba/tip.txt — exit 0), lekin brauzerda bosib sinalmagan. Tezlikni (render soni) o'lchamadik.

3.2 Sxema kutubxonalari

Faqat sxema — vazifalar dagi API sxemasi (vazifa va ro'yxat), uch kutubxonada. Bu yerda React yo'q, faqat sxema kodi:

text
variant                    xom B   gzip B  qator
sxema-valibot               4972     1648      8
sxema-zod                  83576    23653      8
sxema-zodmini              17390     5778      8
Bir xil sxema — kutubxona hajmi (gzip)
  • Zod 4.6.5 (klassik)23,7 KB
  • zod/mini 4.6.55,8 KB
  • Valibot 1.5.01,6 KB

Manba: O'lchandi: sinov/19/tajriba (Vite 8.3.3, gzip -9), natijalar/tajriba/hajm.txt, 2026-10-13

Valibot zod/mini dan ham 4.2 KB kichik. Sababi — tuzilish: har tekshiruv alohida funksiya, bundler ishlatilmaganini tashlaydi ("tree shaking", Tree shaking). zod/mini aynan shu g'oyani Zod'ga olib kirgan (Zod va turni sxemadan chiqarish darsida ko'rgansiz). Klassik Zod bu yerda 23.7 KB — faqat sxema kodi. vazifalar build'ida u +24.2 KB edi (API qatlami darsidagi o'lchov): o'lchov usuli boshqa, xulosa bir xil.

Nega vazifalar da baribir Zod? Uch sabab. Birinchisi — kurs yo'nalishi: Zod — eng keng tarqalgan sxema kutubxonasi, serverda (25-qism) ham shu. Ikkinchisi — 4.2 KB vazifalar ning 153.7 KB idan 3% ga yaqin. Uchinchisi — RHF va Zod jufti eng ko'p hujjat va misolga ega. Bu — halol qaror, "Valibot yomon" degani emas: hajm muhim bo'lgan joyda (vidjet, boshqa saytga qo'yiladigan skript) Valibot to'g'ri tanlov.

4. Standard Schema — umumiy rozetka

4.1 Interfeys

Zod va turni sxemadan chiqarish darsida Standard Schema bilan tanishgansiz: har sxemada ~standard xususiyati bor, ichida validate(value). Natija — { value } yoki { issues }. TanStack Form sxemani resolver'siz qabul qilgani shundan: u Zod'ni bilmaydi, faqat standartni biladi.

zod/mini sxemasi ham standartni qo'llaydi — natija oynasida ko'ramiz:

jsx
import { z } from "zod/mini";

const Name = z
  .string()
  .check(z.trim(), z.minLength(2, "Kamida 2 harf"));
const std = Name["~standard"];
console.log(std.vendor, std.version);
console.log(std.validate("  Ali  "));
console.log(std.validate("A").issues[0].message);

Konsolda:

text
zod 1
{value: 'Ali'}
Kamida 2 harf

vendor — kutubxona nomi, version — standartning versiyasi (1). Muvaffaqiyatda — { value } (kesilgan matn), xatoda — { issues } massivi, har elementida message va path.

4.2 O'z resolveringiz — istalgan sxema uchun

RHF + Zod darsida Zod uchun resolver yozgan edik. Endi u istalgan Standard Schema sxemasi bilan ishlaydi:

jsx
import { useForm } from "react-hook-form";
import { z } from "zod/mini";

function standardResolver(schema) {
  return async (values) => {
    const result = await schema["~standard"].validate(values);
    if (!result.issues) return { values: result.value, errors: {} };
    const errors = {};
    for (const issue of result.issues) {
      const name = (issue.path ?? []).join(".");
      errors[name] ??= { type: "schema", message: issue.message };
    }
    return { values: {}, errors };
  };
}

const Booking = z.object({
  name: z
    .string()
    .check(z.trim(), z.minLength(2, "Ism kamida 2 harf")),
});

export default function App() {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm({
    resolver: standardResolver(Booking),
    defaultValues: { name: "" },
  });
  return (
    <form noValidate onSubmit={handleSubmit((d) => console.log(d))}>
      <p>
        <label htmlFor="name">Ism</label>
        <input id="name" {...register("name")} />
      </p>
      <p role="alert">{errors.name?.message}</p>
      <button>Yuborish</button>
    </form>
  );
}

Ekranda:

text
Ism
Ism kamida 2 harf
Yuborish

standardResolver ichida "zod" so'zi yo'q. Booking ni Valibot yoki ArkType sxemasiga almashtirsangiz, forma o'zgarmaydi. @hookform/resolvers da tayyori bor — @hookform/resolvers/standard-schema (standardSchemaResolver). validate Promise qaytarishi mumkin (async sxema), shuning uchun await.

flowchart LR
  Z["Zod"] --> S["~standard.validate"]
  V["Valibot"] --> S
  A["ArkType"] --> S
  S --> R["RHF (resolver)"]
  S --> T["TanStack Form"]
  S --> C["tRPC, server"]

5. Sxema kutubxonalari

5.1 Valibot

Valibot'da metod zanjiri yo'q — har tekshiruv alohida funksiya, v.pipe bilan ulanadi. Bron sxemasi (Valibot natija oynasida yo'q, shuning uchun bu blok Node'da tekshirilgan):

ts
import * as v from "valibot";

const Booking = v.object({
  name: v.pipe(
    v.string(),
    v.trim(),
    v.minLength(2, "Ism kamida 2 harf"),
  ),
  guests: v.pipe(
    v.string(),
    v.transform(Number),
    v.integer("Butun son yozing"),
    v.minValue(1, "Kamida 1 kishi"),
    v.maxValue(12, "Ko'pi bilan 12 kishi"),
  ),
});
type Booking = v.InferOutput<typeof Booking>;

const ok = v.safeParse(Booking, { name: " Malika ", guests: "4" });
console.log(ok.success && ok.output);
const bad = v.safeParse(Booking, { name: "A", guests: "15" });
console.log(bad.issues?.map((i) => i.message));

Konsolda:

text
{ name: 'Malika', guests: 4 }
[ 'Ism kamida 2 harf', "Ko'pi bilan 12 kishi" ]

Zod bilan solishtiring: z.string().trim().min(2, …) → v.pipe(v.string(), v.trim(), v.minLength(2, …)). coerce yo'q — o'rniga v.transform(Number) quvur ichida. Turni chiqarish — v.InferOutput (va v.InferInput). Natija — output (Zod'da data). Konsol bu yerda Node formatida ({ name: 'Malika', … }).

5.2 ArkType va Yup

Ularni o'lchamadik va kursda o'rnatmadik — faqat ko'rinishi, ular haqida bilish uchun.

ArkType — sxema TypeScript turiga o'xshash satr bilan yoziladi:

ts
import { type } from "arktype";

const Booking = type({
  name: "string >= 2",
  guests: "1 <= number.integer <= 12",
});

"string >= 2" — "kamida 2 belgili satr". TypeScript'ni yaxshi biladigan jamoaga qisqa va tanish; tezligi bilan ham tanilgan. Standard Schema'ni qo'llaydi.

Yup — Zod'dan oldingi davrning eng mashhur sxema kutubxonasi, Formik bilan juftlikda:

js
import * as yup from "yup";

const Booking = yup.object({
  name: yup.string().trim().min(2, "Ism kamida 2 harf").required(),
  guests: yup.number().integer().min(1).max(12).required(),
});

Zanjir Zod'ga o'xshaydi. Farqi — TypeScript turlari keyinroq qo'shilgan, .required() ni har maydonga yozish kerak (sukut bo'yicha ixtiyoriy). Bugun u ham eski (legacy) hisoblanadi: eski Formik loyihalarida ko'p uchraydi.

5.3 Qaysi biri?

Vaziyat Forma Sxema
oddiy SPA, ko'p formalar, katta jamoa RHF Zod / zod/mini
bitta-ikki kichik forma React <form action> zod/mini yoki qo'lda
Next.js server action, JS'siz ham ishlashi kerak Conform yoki <form action> Zod
qattiq type-safe, TanStack ekotizimi TanStack Form Zod / Valibot (Standard Schema)
hajm juda muhim (vidjet, embed) React <form action> Valibot
eski loyiha Formik Yup

Tekshirib ko'ring: Jamoa RHF + Zod dan RHF + Valibot ga o'tmoqchi. Formalarning qaysi qismi o'zgaradi?

Javob

Faqat sxemalar va resolver importi: zodResolver(schema) → valibotResolver(schema) (yoki standardSchemaResolver). register, errors, Controller, useFieldArray — hammasi o'sha. Ajratish shuning uchun foydali: forma va qoidalar mustaqil almashadi. Sxema bilan ishlaydigan boshqa joylar (server, testlar, API qatlami) esa qayta yoziladi — bu o'tishning asosiy narxi.

6. vazifalar da: biz sinab ko'rdik

Bu darsda vazifalar ga qadam yo'q — kanonga hech narsa kirmadi. Lekin qaror o'lchov bilan qilingan. Tajriba fayllari — sinov/19/tajriba/variantlar/forma-*.tsx va sxema-*.tsx, natija — natijalar/tajriba/hajm.txt (Node 24.21.0, Vite 8.3.3, gzip -9, 2026-10-13). Versiyalar tajriba/package.json da aniq yozilgan: Formik 2.4.9, TanStack Form 1.33.5, Conform 1.21.1 (@conform-to/zod bilan), Valibot 1.5.0, RHF 7.89.0, @hookform/resolvers 5.9.1.

Qaror va sabablari:

  • Forma — RHF. Kutubxonasiz variantdan +12.4 KB (vazifalar build'ida +14.7 KB — u yerda tahrir formasining o'z kodi ham qo'shilgan), lekin isDirty, maydon xatolari, Controller, useFieldArray — tahrir formasi va wizard'ga aynan shular kerak edi. Formik — o'xshash hajm, lekin controlled va eski uslub. TanStack Form — +3.6 KB ko'proq va kod uzunroq; bizning formalar oddiy. Conform — server action'lar uchun, bizda esa SPA va soxta API.
  • Sxema — zod/mini. Valibot 4.2 KB kichik — o'lchovda shu ko'rinib turibdi. Lekin Zod — kurs yo'nalishi va server qismlarida ham ishlatiladi. Yakuniy hajmda 4 KB — taxminan 3%.
  • Ro'yxat sahifasidagi tezkor forma — React <form action> (RHF I dagi qaror) — kichik forma uchun kutubxonasiz yo'l.

Raqamlarni o'zingiz ham takrorlay olasiz: har variantni alohida Vite loyihada build qiling (npm run build) va dist/assets dagi JS fayllarning gzip hajmini qo'shing. Biz buni har variantni ketma-ket build qiladigan kichik Node skripti bilan qildik.

7. Ko'p uchraydigan xatolar

Belgi Sabab Davosi
"X kutubxonasi tezroq" — o'lchovsiz qaror maqola yoki reklama raqami o'z formangizni o'lchang (shu darsdagidek)
Formik'da har harfda butun forma sekin controlled — har o'zgarish render FastField yoki RHF; katta formani bo'laklang
Yup'da maydon ixtiyoriy bo'lib qoldi .required() yozilmagan har majburiy maydonga .required()
Valibot'da "4" son emas coerce yo'q v.pipe(v.string(), v.transform(Number), …)
Conform formasi serverdan kelgan xatoni ko'rsatmaydi lastResult uzatilmagan server action natijasini useForm({ lastResult }) ga bering
kutubxona almashtirilganda hamma formalar buzildi forma va sxema aralash yozilgan sxemani alohida faylda, resolver orqali ulang

8. Mashqlar

Mashqlar kurs/mashqlar/19/34-muqobillar/ da.

1-mashq (oson): kutubxonani tanlang

Har vaziyatga «Qaysi biri?» bo'limidagi jadvaldan mosini yozing — forma kutubxonasi nomi bilan (RHF, Formik, Conform, TanStack Form yoki action).

  • Next.js'da obuna formasi, JavaScript'siz ham ishlashi kerak →
  • 40 maydonli admin anketa, dinamik ro'yxatlar →
  • 2019-yilda yozilgan loyihaga yangi maydon qo'shish, u yerda Formik →
  • Bitta maydonli "qidirish" →
Yechim
  • Conform (yoki React <form action> server action bilan) — progressiv yaxshilash.
  • RHF — ko'p maydon, useFieldArray, kam render.
  • Formik — mavjud loyihada o'sha kutubxona; bitta maydon uchun ko'chirish arzimaydi.
  • action — React'ning <form action>, kutubxona kerak emas.

2-mashq (o'rta): Standard Schema bilan tekshiruvchi

check(schema, value) funksiyasini yozing. U istalgan Standard Schema sxemasini oladi va qaytaradi: muvaffaqiyatda — "✓ " + qiymat, xatoda — "✗ " + xabarlar ("; " bilan). Uni ikki xil sxema bilan sinang: klassik zod va zod/mini (ikkalasi ham natija oynasida bor).

jsx
import { z } from "zod";
import { z as mini } from "zod/mini";

function check(schema, value) {
  // shu yerga
  return "?";
}

const Price = z.coerce.number().min(1000, "Kamida 1 000 so'm");
const Dish = mini.string().check(mini.minLength(2, "Nom qisqa"));
console.log(check(Price, "35000"));
console.log(check(Dish, "O"));

Konsolda:

text
?
?
Yechim
jsx
import { z } from "zod";
import { z as mini } from "zod/mini";

function check(schema, value) {
  const result = schema["~standard"].validate(value);
  if (result instanceof Promise) return "✗ async sxema";
  if (result.issues) {
    return "✗ " + result.issues.map((i) => i.message).join("; ");
  }
  return "✓ " + result.value;
}

const Price = z.coerce.number().min(1000, "Kamida 1 000 so'm");
const Dish = mini.string().check(mini.minLength(2, "Nom qisqa"));
console.log(check(Price, "35000"));
console.log(check(Dish, "O"));
console.log(check(Price, "500"));

Konsolda:

text
✓ 35000
✗ Nom qisqa
✗ Kamida 1 000 so'm

check hech qaysi kutubxonani import qilmaydi — faqat ~standard ga murojaat qiladi. Ikki xil "Zod" — bir xil natija. Valibot sxemasi ham shu funksiyaga to'g'ridan tushadi (Zod va turni sxemadan chiqarish darsidagi check misolining o'zi, endi brauzerda).

3-mashq (qiyin): xatolar ro'yxati — criteriaMode: "all"

«Standard Schema» bo'limidagi standardResolver har maydonga birinchi xatoni qo'yadi. Uni kengaytiring: maydonning barcha xabarlari types obyektida bo'lsin ({ type, message, types: { "0": "…", "1": "…" } }) — RHF criteriaMode: "all" da shu ko'rinishni kutadi. Parol maydoni (password): kamida 8 belgi va kamida bitta raqam. Ekranda hamma xabarlar ro'yxat bo'lib chiqsin.

Ishora: sxemada ikki qoida — mini.minLength(8, …) va mini.regex(/\d/, …). zod/mini birinchi xatodan keyin to'xtamaydi — ikkalasi ham issues da bo'ladi. Ekranda: Object.values(errors.password?.types ?? {}).

Yechim
jsx
import { useForm } from "react-hook-form";
import { z } from "zod/mini";

function standardResolver(schema) {
  return async (values) => {
    const result = await schema["~standard"].validate(values);
    if (!result.issues) return { values: result.value, errors: {} };
    const errors = {};
    for (const issue of result.issues) {
      const name = (issue.path ?? []).join(".");
      errors[name] ??= {
        type: "schema",
        message: issue.message,
        types: {},
      };
      const types = errors[name].types;
      types[Object.keys(types).length] = issue.message;
    }
    return { values: {}, errors };
  };
}

const Account = z.object({
  password: z.string().check(
    z.minLength(8, "Kamida 8 belgi"),
    z.regex(/\d/, "Kamida bitta raqam"),
  ),
});

export default function App() {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm({
    resolver: standardResolver(Account),
    criteriaMode: "all",
    defaultValues: { password: "" },
  });
  const messages = Object.values(errors.password?.types ?? {});
  return (
    <form noValidate onSubmit={handleSubmit(() => console.log("ok"))}>
      <p>
        <label htmlFor="password">Parol</label>
        <input
          id="password"
          type="password"
          {...register("password")}
        />
      </p>
      <ul>
        {messages.map((m) => (
          <li key={m}>{m}</li>
        ))}
      </ul>
      <button>Yuborish</button>
    </form>
  );
}

Ekranda:

text
Parol
Kamida 8 belgi
Kamida bitta raqam
Yuborish

Mehmon bir vaqtda ikkala talabni ko'radi — birini tuzatib, yana yuborib, ikkinchisini bilishi shart emas. Parol misoli — faqat qoidalar uchun; parol maydoni qoralamaga yozilmaydi va konsolga chiqarilmaydi (RHF III).

9. Real ishda

  • Ish e'lonlarida ko'pincha "React Hook Form + Zod" yoziladi; Formik va Yup — eski loyihalar uchun. Ikkalasini o'qiy olish — afzallik.
  • Next.js loyihalari — server action'lar bilan Conform yoki React'ning useActionState i (Server Actions II); RHF ham ishlatiladi, lekin u holda forma JavaScript'ga tayanadi.
  • Kutubxona tanlash — Paket tanlash va baholash darsidagi mezonlar: hajm (o'lchang!), yangilanish tezligi, yuklab olishlar, TypeScript, jamoa tajribasi.
  • Intervyu savollari: "RHF va Formik farqi?", "Standard Schema nima?", "nega Valibot kichik?", "JavaScript'siz ishlaydigan forma qanday quriladi?".

Xulosa

  • Forma kutubxonasi va sxema kutubxonasi — alohida tanlov; Standard Schema (~standard.validate) ularni bog'laydi.
  • O'lchov (gzip, React bilan): <form action> 72.2, Formik 84.2, RHF 84.6, TanStack Form 88.3, Conform 93.7 KB. Sxema: Zod 23.7, zod/mini 5.8, Valibot 1.6 KB.
  • Formik — controlled, eski loyihalar; TanStack Form — to'liq type-safe; Conform — server action, JavaScript'siz ishlaydi.
  • Valibot — eng kichik (funksiyalar + pipe), ArkType — tur-satr sintaksisi, Yup — eski, Formik juftligi.
  • vazifalar — RHF + zod/mini: o'lchangan, sabablari yozilgan qaror; tezkor forma — kutubxonasiz.

Keyingi dars: Maxsus inputlar: telefon, sana, OTP, raqam va combobox — +998 telefon maskasi, OTP kod, sana va so'm formatlash, ARIA combobox; vazifalar ga teg combobox'i.

Manbalar

  • Standard Schema — standardschema.dev (spetsifikatsiya v1)
  • Formik — formik.org/docs (2.4.9); TanStack Form — tanstack.com/form/latest (1.33.5); Conform — conform.guide (1.21.1)
  • Valibot — valibot.dev (1.5.0); ArkType — arktype.io; Yup — github.com/jquense/yup
  • @hookform/resolvers — github.com/react-hook-form/resolvers (standard-schema, valibot)
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
Forma va validatsiya kutubxonalari: Formik, TanStack Form, Conform, Valibot va Standard Schema — IlmHamroh