IlmHamroh
JavaScript Full-stack/19-qism. React: routing, server state, formalar8/36-dars16 daqiqa
Mundarija (27)

TanStack Router: to'liq type-safe routing, validateSearch va React Router bilan o'lchab taqqoslash

Qisqacha: TanStack Router — React uchun router, unda yo'llar, parametrlar va so'rov parametrlari (search params) TypeScript turlari bilan tekshiriladi. Masalan, <Link to="/vazifalar/$id"> — yo'q yo'l bo'lsa, tsc xato beradi. params.id — son, chunki marshrut uni bir marta parse qiladi. validateSearch (masalan, Zod sxemasi bilan) ?sahifa=abc ni ham tozalaydi. vazifalar da o'lchandi: 93.2 KB (React Router — 97.3), ataylab yozilgan 4 xatoni tsc ushladi, React Router — birortasini ham. Kanon React Router'da qoldi: kurs ekotizimi va Next.js'ga ko'prik.

Bu darsda

  • "Type-safe routing" nimani anglatishini va React Router qayerda "jim" qolishini ko'rasiz.
  • TanStack Router'da marshrut daraxtini kod bilan qurasiz: createRootRoute, createRoute, createRouter va Register.
  • Parametrlarni parse/stringify bilan son qilasiz, so'rov parametrlarini validateSearch va Zod bilan tekshirasiz.
  • Fayl asosidagi marshrutlar (@tanstack/router-plugin), devtools va TanStack Start nima ekanini bilasiz.
  • Kanon o'lchovini o'qib, qaysi loyihaga qaysi router mosligini tanlay olasiz.

Oldin bilishingiz kerak: React Router IV: data mode, Union va literal turlar, Zod va turni sxemadan chiqarish.

1. Nega bu kerak?

Sardor vazifalar ga yangi havola qo'shdi: <Link to={`/vazifalar/${id}`}>. Ko'zi tushmadi — marshrut /vazifa/:id, oxirida ortiqcha "lar". tsc indamadi, ESLint indamadi, testlar o'tdi. Foydalanuvchi bosdi — 404.

Boshqa safar useParams() dan params.idd deb o'qidi (imlo xatosi). Natija — undefined, Number(undefined) — NaN, vazifa "topilmadi". Yana hech kim ogohlantirmadi.

Sabab bitta: React Router uchun yo'l — oddiy satr. U qanday marshrutlar borligini TypeScript'ga aytmaydi. 06-darsda framework mode'ning typegen'i buni qisman hal qilishini ko'rdik — lekin u alohida build qadami va Vite plagini bilan. TanStack Router boshqacha yo'l tutadi: marshrut daraxtining o'zi TypeScript turi, hech qanday generatsiyasiz.

Hayotiy o'xshatish: taksi navigatori. Biri manzilni qo'lda yozdirib, xato bo'lsa haydab ketib, joyida "bunday ko'cha yo'q" deydi. Ikkinchisi manzilni faqat xaritadagi ro'yxatdan tanlatadi — noto'g'ri ko'chani tanlab bo'lmaydi.

2. "Jim" xatolar: React Router'da qanday ko'rinadi

2.1 useParams() — har kalit mumkin

React Router'da useParams() ning turi — { [key: string]: string | undefined }. Ya'ni har qanday kalit "bor bo'lishi mumkin". Quyidagi blok — TypeScript (tsx): sayt uni tsc bilan tekshiradi va ishga tushiradi. Imlo xatosiga qaramay, tur tekshiruvi xatosiz o'tadi:

tsx
import {
  createMemoryRouter,
  RouterProvider,
  useParams,
} from "react-router";

function Task() {
  const params = useParams();
  const id = Number(params.idd); // imlo xatosi: idd
  return <p>Vazifa raqami: {String(id)}</p>;
}

const router = createMemoryRouter(
  [{ path: "/vazifa/:id", element: <Task /> }],
  { initialEntries: ["/vazifa/2"] },
);

export default function App() {
  return <RouterProvider router={router} />;
}

Ekranda:

text
Vazifa raqami: NaN

Sahifa — NaN, tsc ham, brauzer ham indamadi. Kanon tajribasida (tajriba/tip-xatolar/router-xato.tsx) xuddi shu qator bor va izohi: "idd — imlo xatosi, tsc indamaydi".

2.2 Yo'llar ro'yxati — tur bo'lsa

Bu muammoni qanday hal qilish mumkin? Barcha yo'llarni literal turlar birlashmasi qilib yozamiz. Shunda Link faqat ro'yxatdagi yo'lni qabul qiladi:

tsx
type RoutePath = "/" | "/vazifa/$id" | "/statistika";

function linkTo(to: RoutePath): string {
  return to;
}

linkTo("/vazifa/$id");
linkTo("/vazifalar/$id");

Xato:

text
TS2345: Argument of type '"/vazifalar/$id"' is not assignable to parameter of type 'RoutePath'.

Ikkinchi chaqiruv qizil: "/vazifalar/$id" turi RoutePath ga mos emas. TanStack Router shu g'oyani oxirigacha olib boradi. Yo'llar ro'yxatini siz yozmaysiz — u marshrut daraxtidan o'zi chiqariladi. Har yo'lning parametrlari ($id), ularning turi (son) va so'rov parametrlari ham turga kiradi.

3. TanStack Router: marshrut daraxti kod bilan

3.1 O'rnatish va narxi

bash
npm i --save-exact @tanstack/react-router@1.170.41

Kanon tajribasidagi versiya — 1.170.41 (2026-09-30; o'lchov kunida eng yangisi 1.170.44 edi, 7 kundan yangi bo'lgani uchun olinmadi — natijalar/versiyalar.txt). Natija oynasida bu paket yo'q — saytdagi «Ishga tushir» faqat React Router'ni yuklaydi. Shuning uchun bu bo'limdagi TanStack kodlari tekshirilmagan bloklar; ularning hammasi kanon tajriba faylidan aynan olingan va tsc dan o'tgan.

3.2 Uch sahifa — router-tanstack.tsx

vazifalar ning o'sha uch sahifasi (kanon tajribasi, aynan; uzun qatorlar telefon uchun bo'lingan):

tsx
import {
  createRootRoute,
  createRoute,
  createRouter,
  Link,
  notFound,
  Outlet,
  RouterProvider,
} from "@tanstack/react-router";

const ildizMarshrut = createRootRoute({
  component: () => (
    <>
      <nav>
        <Link to="/">Ro'yxat</Link>
      </nav>
      <Outlet />
    </>
  ),
  notFoundComponent: () => <p>Topilmadi</p>,
});

const royxatMarshrut = createRoute({
  getParentRoute: () => ildizMarshrut,
  path: "/",
  component: () => (
    <ul>
      {VAZIFALAR.map((v) => (
        <li key={v.id}>
          <Link to="/vazifa/$id" params={{ id: v.id }}>
            {v.matn}
          </Link>
        </li>
      ))}
    </ul>
  ),
});

Tanish narsalar boshqa nom bilan:

TanStack Router React Router Izoh
createRootRoute({ component }) ildiz { path: "/", element } layout, <Outlet /> — o'sha
createRoute({ getParentRoute, path }) children ichidagi obyekt ota — funksiya bilan
$id :id dinamik segment
notFoundComponent { path: "*" } 404
<Link to params> <Link to={`/vazifa/${id}`}> parametr — alohida obyekt

Eng muhim farq — oxirgi qatorda. Yo'l — shablon ("/vazifa/$id"), parametr — alohida. Shuning uchun tsc ikkalasini ham tekshira oladi: shablon ro'yxatdami, params da aynan id bormi.

Tekshirib ko'ring: React Router'da <Link to={/vazifa/${v.id}}> yozardik. TanStack'da nega params={{ id: v.id }} alohida beriladi — bitta satr qulayroq emasmi?

Javob

Bitta satr — TypeScript uchun "qandaydir satr": u ichidagi /vazifa/ ni ham, ${v.id} ni ham ajrata olmaydi. Shablon ("/vazifa/$id") va parametrlar obyekti alohida bo'lsa, tsc ikkita aniq savolga javob beradi: shablon ro'yxatdami va params aynan shu shablon kutgan kalitlarga egami. Narxi — biroz uzunroq yozuv.

getParentRoute: () => ildizMarshrut — nega funksiya? TypeScript turni ota marshrutdan oladi. Funksiya aylana importlarda (fayllar bir-birini import qilsa) ham ishlaydi.

3.3 Parametr — bir marta parse

tsx
export const vazifaMarshrut = createRoute({
  getParentRoute: () => ildizMarshrut,
  path: "/vazifa/$id",
  // URL'dagi satr → son (bir marta, shu yerda); stringify —
  // teskarisi
  params: {
    parse: (p) => ({ id: Number(p.id) }),
    stringify: (p) => ({ id: String(p.id) }),
  },
  loader: ({ params }) => {
    const v = VAZIFALAR.find((x) => x.id === params.id);
    if (!v) throw notFound();
    return v;
  },
  component: function Vazifa() {
    const v = vazifaMarshrut.useLoaderData();
    return <h2>{v.matn}</h2>;
  },
});
  • params.parse — URL'dan kelgan satrni bir marta, marshrut darajasida songa aylantiradi. Loader'da params.id — number, Number(...) ni har joyda takrorlash yo'q. 03-darsdagi "parametr doim satr" qoidasini marshrutning o'zi hal qiladi.
  • stringify — teskari yo'l: <Link params={{ id: 2 }}> dagi sonni manzilga yozish uchun.
  • loader — React Router'dagidek: sahifadan oldin. throw notFound() — data(…, { status: 404 }) o'rni.
  • vazifaMarshrut.useLoaderData() — hook marshrut obyektining o'zidan. Turni loader'dan oladi: v.matn — string, typeof yozish shart emas.

3.4 Register — router'ni TypeScript'ga tanishtirish

tsx
export const router = createRouter({
  routeTree: ildizMarshrut.addChildren([
    royxatMarshrut,
    vazifaMarshrut,
  ]),
});
declare module "@tanstack/react-router" {
  interface Register {
    router: typeof router;
  }
}

addChildren — daraxtni yig'adi. Keyingi qism — module augmentation: kutubxonaning Register interfeysiga bizning router turimiz qo'shiladi. Shundan keyin ilovaning istalgan joyidagi <Link> hamma yo'llarni biladi. Bu qadam unutilsa, Link ham oddiy satr qabul qiladigan bo'lib qoladi — type-safety jimgina o'chadi.

4. O'lchov: tsc nimani ushladi

Kanon ataylab xato fayl yozdi (tajriba/tip-xatolar/router-xato.tsx, aynan):

tsx
export function Xatolar() {
  const rr = useParams(); // xato bo'lsa ham jim
  const id: number = Number(rr.idd); // "idd" — tsc indamaydi
  return (
    <>
      {/* 1) mavjud bo'lmagan yo'l */}
      <TLink to="/vazifalar/$id" params={{ id: 1 }} />
      {/* 2) parametr nomi xato */}
      <TLink to="/vazifa/$id" params={{ idd: 1 }} />
      {/* 3) parametr turi xato (parse — son kutadi) */}
      <TLink to="/vazifa/$id" params={{ id: "bir" }} />
      {/* React Router: shu xatolar — tsc jim (satr shablon) */}
      <RLink to={`/vazifalar/${id}`} />
    </>
  );
}

TLink — TanStack'ning Link, RLink — React Router'niki. tsc 7.0.2 natijasi (natijalar/tajriba/08-tanstack-tip.txt, uzun tur matnlari qisqartirilgan):

text
router-xato.tsx(14,14): error TS2820: Type '"/vazifalar/$id"' is not assignable to type '"." | ".." | "/" | "/vazifa/$id"'. Did you mean '"/vazifa/$id"'?
router-xato.tsx(14,44): error TS2353: Object literal may only specify known properties, and 'id' does not exist in type 'ParamsReducerFn<…>'.
router-xato.tsx(16,41): error TS2353: Object literal may only specify known properties, and 'idd' does not exist in type 'ParamsReducerFn<…>'.
router-xato.tsx(18,41): error TS2322: Type 'string' is not assignable to type 'number'.

To'rtta xato, uchta qatorda. Ularni o'qiymiz:

  1. TS2820 — "/vazifalar/$id" yo'llar ro'yxatiga mos emas. Ro'yxat ham ko'rsatilgan: "." | ".." | "/" | "/vazifa/$id". Va maslahat: "/vazifa/$id ni nazarda tutdingizmi?"
  2. TS2353 (14-qator) — yo'l noma'lum bo'lgani uchun params dagi id ham "ortiqcha". Bitta xato — ikkita xabar, bu tabiiy.
  3. TS2353 (16-qator) — idd — bunday parametr yo'q.
  4. TS2322 — id: "bir" — satr, parse esa son qaytaradi, params son kutadi.

React Router qatorlari (rr.idd va RLink) — birorta ham xato yo'q. Uzun ParamsReducerFn<RouterCore<…>> matni — TanStack turlarining narxi: xato xabarlari ba'zan juda uzun. Asosiy qismi — boshida va oxirida.

Ataylab yozilgan router xatolari — tsc ushladi
  • React Router 8.4.0 (data mode)0 ta
  • TanStack Router 1.170.414 ta

Manba: O'lchandi: tajriba/tip-xatolar/router-xato.tsx, tsc 7.0.2, natijalar/tajriba/08-tanstack-tip.txt, 2026-10-13

5. So'rov parametrlari: validateSearch

5.1 Muammo: ?sahifa=abc

04-darsda useSearchParams() bilan ishladik: qiymat — satr yoki null, tekshirish — har komponentda qo'lda. ?sahifa=abc, ?saralash=pitsa — URL'ni har kim yozadi.

TanStack Router so'rov parametrlarini ham marshrutga bog'laydi. validateSearch — URL'dagi xom obyektni oladi va tekshirilgan, turli obyekt qaytaradi:

tsx
const menyuMarshrut = createRoute({
  getParentRoute: () => ildizMarshrut,
  path: "/menyu",
  validateSearch: (search: Record<string, unknown>) => ({
    sahifa: Number(search.sahifa ?? 1) || 1,
    turi: search.turi === "ichimlik" ? "ichimlik" : "hammasi",
  }),
});
// komponentda: const { sahifa, turi } = menyuMarshrut.useSearch();
// sahifa — number, turi — "ichimlik" | "hammasi"
// <Link to="/menyu" search={{ sahifa: 2 }}> — turi tekshiriladi

Funksiya o'rniga Zod sxemasini ham berish mumkin: TanStack Router Standard Schema'ni (Zod 4, Valibot ham shu standartda) to'g'ridan qabul qiladi. Bu blok o'lchanmagan — kanon tajribasida validateSearch yo'q edi.

5.2 Xuddi shu g'oya — React Router'da, Zod bilan

TanStack'siz ham bu naqshni qo'llash mumkin. Sxema bir marta yoziladi, komponent tekshirilgan qiymat oladi. Natija oynasida zod/mini bor (kanondagi Zod — API qatlami darsida batafsil):

jsx
import {
  createMemoryRouter,
  RouterProvider,
  useLocation,
  useSearchParams,
} from "react-router";
import * as z from "zod/mini";

// URL — foydalanuvchi kiritgan ma'lumot: tekshir, yaroqsizini
// almashtir
const menuSearch = z.object({
  sahifa: z.catch(z.coerce.number().check(z.int(), z.positive()), 1),
  turi: z.catch(z.enum(["hammasi", "ichimlik"]), "hammasi"),
});

function useMenuSearch() {
  const [params, setParams] = useSearchParams();
  const search = menuSearch.parse(Object.fromEntries(params));
  return [search, setParams];
}

function Menu() {
  const { search: raw } = useLocation();
  const [search, setParams] = useMenuSearch();
  return (
    <section>
      <p>URL: {raw}</p>
      <p>
        Sahifa {search.sahifa}, turi: {search.turi}
      </p>
      <button
        onClick={() =>
          setParams({ sahifa: String(search.sahifa + 1) })
        }
      >
        Keyingi
      </button>
    </section>
  );
}

const router = createMemoryRouter(
  [{ path: "/menyu", element: <Menu /> }],
  { initialEntries: ["/menyu?sahifa=abc&turi=pitsa"] },
);

export default function App() {
  return <RouterProvider router={router} />;
}

Ekranda:

text
URL: ?sahifa=2
Sahifa 2, turi: hammasi
Keyingi

Ilova ?sahifa=abc&turi=pitsa bilan ochildi — ikkalasi ham yaroqsiz. z.catch(…, 1) — "tekshiruvdan o'tmasa, shu qiymat": sahifa 1, turi "hammasi". «Keyingi» — sahifa=2. z.coerce.number() — satrni songa aylantiradi (Zod chuqurroq darsida). Komponent hech qachon NaN yoki "pitsa" ni ko'rmaydi.

Farq: bu yerda search.sahifa turi JavaScript'da tekshirilmaydi, TypeScript'da esa faqat useMenuSearch ichida ma'lum. <Link to="/menyu?sahifa=abc"> ni yozishga hech narsa to'sqinlik qilmaydi. TanStack'da search={{ sahifa: "abc" }} — tsc xatosi.

Tekshirib ko'ring: Yuqoridagi ilova /menyu?sahifa=-3 bilan ochilsa, ekranda qaysi sahifa? /menyu?sahifa=2.5 chi?

Javob

Ikkalasida ham 1. -3 — son, lekin z.positive() dan o'tmaydi. 2.5 — z.int() dan o'tmaydi. Har qanday tekshiruv xatosida z.catch zaxira qiymatni beradi. Sxemasiz Number("-3") — -3 bo'lardi va ro'yxat "−3-sahifa" ni qidirardi.

6. Fayl asosidagi marshrutlar, devtools va TanStack Start

Fayl asosidagi marshrutlar (file-based routing). Katta ilovada createRoute ni qo'lda yozish o'rniga @tanstack/router-plugin (Vite plagini) ishlatiladi. Fayllar src/routes/ da: __root.tsx, index.tsx, vazifa.$id.tsx. Plagin ulardan routeTree.gen.ts faylini generatsiya qiladi — yuqoridagi addChildren daraxtining o'zi. Har marshrut fayli createFileRoute("/vazifa/$id")({ … }) bilan boshlanadi. Hujjat shu yo'lni tavsiya qiladi. Kanon tajribasi kod bilan ("generator'siz") yozilgan — daraxt ko'rinib tursin.

Devtools. @tanstack/react-router-devtools — dev rejimida sahifa burchagidagi panel: joriy marshrutlar, parametrlar, loader holati, kesh. React Router'da bunday rasmiy panel yo'q.

TanStack Start — shu router ustiga qurilgan full-stack framework: SSR, server funksiyalar. React Router'ning framework mode'iga (06-dars) yoki Next.js'ga muqobil. Bu kursda o'tilmaydi — nomini eshitsangiz, nima ekanini bilasiz.

Kesh va TanStack Query. TanStack Router loader natijasini o'zi keshlaydi (staleTime bilan) va TanStack Query bilan oson birlashadi. Query'ni TanStack Query I darsidan o'rganamiz.

7. Kanon tajribasi: nega vazifalar React Router'da qoldi

7.1 Hajm

Uch sahifa: brauzer yuklaydigan JS (gzip)
  • faqat React66,5 KB
  • TanStack Router 1.170.4193,2 KB
  • React Router 8.4.097,3 KB

Manba: O'lchandi: tajriba/qur.mjs, Vite 8.3.3, gzip -9, natijalar/tajriba/hajm.txt (router-tanstack 93 247 B, router-rr 97 262 B, _umumiy 66 470 B), 2026-10-13

TanStack Router 4 KB kichik (93 247 va 97 262 bayt). Ikkalasi ham bir xil ishni qiladi: layout, ro'yxat, loader'li vazifa sahifasi, 404. Ikkalasi ham faqat build qilindi va tsc dan o'tdi — brauzerda bosib solishtirilmadi.

7.2 Qaror

QADAMLAR (19/#08): kirmadi. Sabablar:

  • Yo'nalish — kurs ekotizimi React Router: data mode g'oyalari (loader, action, <Form>) to'g'ridan Next.js qismiga ko'prik. React Router — npm'da eng ko'p yuklanadigan React router'i; ish e'lonlarida ham u ko'proq.
  • Ko'chish narxi — 02–07 darslarda qurilgan hamma narsa (marshrutlar, Himoyalangan, loader, 45 ta e2e tekshiruv) qayta yoziladi.

Lekin raqamlar halol: TanStack kichikroq va type-safe — kanon buni TEXNIK-QARZ.md ga (46-band) yozib qo'ygan. Shunday vaziyatda TanStack Router to'g'ri tanlov bo'ladi:

  • yangi, katta TypeScript ilova — o'nlab sahifa, ko'p filtr va so'rov parametri (admin panel, CRM);
  • jamoa TanStack Query'ni allaqachon ishlatadi;
  • URL holati ko'p (?sahifa=&saralash=&filtr=) — validateSearch uni bir joyga yig'adi.

React Router ham shu yo'nalishda yuryapti: framework mode'dagi typegen (06-dars) href() va Route.ComponentProps orqali yo'l va parametrlarni tekshiradi. Farqi — TanStack'da turlar marshrut kodining o'zidan chiqadi, React Router'da esa alohida generatsiya qadami va Vite plagini kerak. Data mode'da (bizning vazifalar) bu tekshiruv yo'q. Shuning uchun vazifalar da yo'llar testlar bilan himoyalangan: 19-qismning e2e tekshiruvlari asosiy havolalarni brauzerda bosib ko'radi.

Kichik ilova yoki SSR kerak bo'lgan ochiq sayt uchun — React Router (framework mode) yoki Next.js.

8. Ko'p uchraydigan xatolar

Belgi Sabab Davosi
Link har qanday satrni qabul qiladi Register e'lon qilinmagan declare module … interface Register { router: typeof router }
TS2820: … Did you mean … yo'l ro'yxatda yo'q maslahat qilingan yo'lni yozing
params.id — satr, === 2 hech qachon true emas params.parse yo'q parse: (p) => ({ id: Number(p.id) })
uzun ParamsReducerFn<RouterCore<…>> xabar murakkab generic turlar xabarning boshi va oxirini o'qing: qaysi kalit, qaysi tur
routeTree.gen.ts topilmadi plagin ishlamagan @tanstack/router-plugin Vite'da, dev serverni qayta ishga tushiring
React Router'da ?sahifa=abc → NaN qiymat tekshirilmagan sxema (z.catch) bilan bir joyda o'qish

9. Mashqlar

Mashqlar kurs/mashqlar/19/08-tanstack-router/ da.

1-mashq (oson): qaysi xato?

TanStack Router'da / va /taom/$slug marshrutlari bor (slug — satr). Har qatorga tsc nima deydi: "toza" yoki xato kodi (TS2820, TS2353, TS2322)?

  1. <Link to="/taom/$slug" params={{ slug: "osh" }} /> →
  2. <Link to="/taomlar/$slug" params={{ slug: "osh" }} /> →
  3. <Link to="/taom/$slug" params={{ nom: "osh" }} /> →
Yechim

1 — toza. 2 — TS2820: yo'l ro'yxatda yo'q (va TS2353 ham chiqishi mumkin — «O'lchov» bo'limidagi 14-qatordagidek, yo'l noma'lum bo'lsa parametr ham "ortiqcha"). 3 — TS2353: nom degan parametr yo'q, slug kerak. React Router'da uchala qator ham tsc dan jim o'tardi.

2-mashq (o'rta): literal tur bilan yo'l

RoutePath turini yozing ("/", "/menyu", "/taom/$slug") va linkTo funksiyasi faqat shularni qabul qilsin. $slug ni slug qiymati bilan almashtirsin. Ishora: «Yo'llar ro'yxati — tur bo'lsa» bo'limi va satrning replace metodi.

Yechim
tsx
type RoutePath = "/" | "/menyu" | "/taom/$slug";

function linkTo(to: RoutePath, slug = ""): string {
  return to.replace("$slug", slug);
}

console.log(linkTo("/menyu"));
console.log(linkTo("/taom/$slug", "osh"));

export default function App() {
  return <a href={linkTo("/taom/$slug", "manti")}>Manti</a>;
}

Konsolda:

text
/menyu
/taom/osh

Ekranda:

text
Manti

linkTo("/taomlar/$slug") endi tsc xatosi beradi. Kamchilik: "/menyu" ga ham slug berish mumkin, "/taom/$slug" ga esa bermaslik ham mumkin. TanStack Router buni ham hal qiladi: parametrlar yo'lga qarab majburiy yoki taqiqlangan bo'ladi — bunga bitta conditional type kerak.

3-mashq (qiyin): URL sxemasi

«Bahor» buyurtmalar sahifasi /buyurtmalar?holat=…&saralash=…. Sxema yozing:

  1. holat — "yangi" | "tayyor" | "hammasi", noto'g'ri bo'lsa "hammasi".
  2. saralash — "vaqt" | "narx", sukut "vaqt".
  3. Ekranda: Holat: …, saralash: …. «Tayyorlar» tugmasi holat=tayyor ni qo'ysin, saralash ni saqlagan holda.

Ilova /buyurtmalar?holat=bekor&saralash=narx bilan ochilsin. Ishora: «Xuddi shu g'oya — React Router'da» bo'limi va 04-darsdagi funksiya bilan setSearchParams.

Yechim
jsx
import {
  createMemoryRouter,
  RouterProvider,
  useSearchParams,
} from "react-router";
import * as z from "zod/mini";

const ordersSearch = z.object({
  holat: z.catch(z.enum(["yangi", "tayyor", "hammasi"]), "hammasi"),
  saralash: z.catch(z.enum(["vaqt", "narx"]), "vaqt"),
});

function Orders() {
  const [params, setParams] = useSearchParams();
  const search = ordersSearch.parse(Object.fromEntries(params));
  return (
    <section>
      <p>
        Holat: {search.holat}, saralash: {search.saralash}
      </p>
      <button
        onClick={() =>
          setParams((prev) => {
            prev.set("holat", "tayyor");
            return prev;
          })
        }
      >
        Tayyorlar
      </button>
    </section>
  );
}

const router = createMemoryRouter(
  [{ path: "/buyurtmalar", element: <Orders /> }],
  { initialEntries: ["/buyurtmalar?holat=bekor&saralash=narx"] },
);

export default function App() {
  return <RouterProvider router={router} />;
}

Ekranda:

text
Holat: tayyor, saralash: narx
Tayyorlar

Ochilganda holat=bekor yaroqsiz — "hammasi", saralash=narx — to'g'ri, saqlandi. «Tayyorlar» funksiya bilan yozdi — saralash yo'qolmadi. saralash URL'da bo'lmasa ham "vaqt" bo'lardi: z.catch yo'q qiymatni ham ushlaydi (undefined enum'dan o'tmaydi).

4-mashq: vazifalar ga nazar

Darsdagi TanStack kodini («Parametr — bir marta parse») data mode darsidagi vazifaLoader bilan solishtiring. Har birida vazifa raqami URL'dan songa qayerda aylanadi?

Yechim

React Router variantida — loader ichida (raqaminiOl → Number(id)); har yangi joyda qaytadan yoziladi. TanStack variantida — marshrut ta'rifida bir marta: params.parse. Loader ham, Link ham songa ishlaydi (params={{ id: v.id }} — son), satrga aylantirishni stringify qiladi. Shu sababli 3-xato (id: "bir") TanStack'da tsc xatosi.

10. Real ishda

  • Katta TypeScript ilovalar — TanStack Router 2023-yildan beri tez o'smoqda, ayniqsa admin panel va SaaS loyihalarda, TanStack Query bilan birga.
  • Migratsiya — React Router'dan TanStack'ga ko'chish odatda bosqichma-bosqich emas, bir martada (ikki router birga ishlamaydi). Shuning uchun tanlov loyiha boshida qilinadi.
  • URL holati — validateSearch naqshi kutubxonasiz ham foydali: sxema + bitta hook. Keyingi darsda nuqs kutubxonasini ko'ramiz.
  • Intervyu savollari: "type-safe routing nima beradi?", "params qachon satr, qachon son?", "URL'dagi qiymatni qanday tekshirasiz?".

Xulosa

  • React Router'da yo'l va useParams() — oddiy satr: imlo xatosi tsc dan jim o'tadi.
  • TanStack Router: createRootRoute, createRoute({ getParentRoute, path }), createRouter + Register — yo'llar turga aylanadi.
  • params.parse — parametr bir marta, marshrutda songa; validateSearch — so'rov parametrlari sxema bilan.
  • O'lchov: 93.2 vs 97.3 KB, ataylab yozilgan 4 xato — TanStack ushladi, React Router — 0.
  • Fayl asosidagi marshrutlar — @tanstack/router-plugin; devtools; TanStack Start — full-stack.
  • Kanon React Router'da qoldi (ekotizim, Next.js ko'prigi, ko'chish narxi); yangi katta TS ilova uchun TanStack — kuchli nomzod.

Keyingi dars: URL — holat saqlash joyi — filtr, saralash va sahifa URL'da: nuqs, standart qiymatlarni tozalash, push va replace. vazifalar ning filtri router'ga ko'chadi.

Manbalar

  • TanStack Router: Overview, Code-based Routing, Type Safety, Search Params — tanstack.com/router/latest/docs (2026-10 holatiga, v1.170)
  • TanStack Router: File-based Routing, Router Plugin, Devtools — tanstack.com/router/latest/docs/framework/react
  • React Router: useParams — reactrouter.com/api/hooks/useParams
  • Zod 4: zod/mini, catch, coerce — zod.dev
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
TanStack Router: to'liq type-safe routing, validateSearch va React Router bilan o'lchab taqqoslash — IlmHamroh