Mundarija (28)
- Bu darsda
- 1. Nega bu kerak?
- 2. Remix'dan React Router 7 gacha
- 3. Framework mode tuzilmasi
- 3.1 Paketlar va buyruqlar
- 3.2 Ikki konfiguratsiya fayli
- 3.3 app/root.tsx — index.html o'rnida
- 3.4 app/routes.ts — marshrutlar xaritasi
- 3.5 Route modul — bitta faylda bitta sahifa
- 3.6 Route modul — aslida route obyekt
- 4. Typegen — turlar o'zi yoziladi
- 4.1 Route.ComponentProps qayerdan keladi?
- 4.2 href() — yo'l tekshiruvchi
- 5. SSR, SPA va prerender
- 5.1 Uch yo'l — bitta kod
- 5.2 Nega "bo'sh HTML" muhim?
- 6. Kanon tajribasi: vazifalar framework mode'da
- 6.1 O'lchov
- 6.2 Nega kanonga kirmadi
- 7. Ko'p uchraydigan xatolar
- 8. Mashqlar
- 1-mashq (oson): qaysi fayl?
- 2-mashq (o'rta): modulni ulang
- 3-mashq (qiyin): o'z routes.ts ingiz
- 4-mashq: vazifalar ga nazar
- 9. Real ishda
- Xulosa
- Manbalar
React Router framework mode: routes.ts, route modullari, typegen va SSR/SPA rejimlari
Qisqacha: Framework mode — data mode ustiga qo'yilgan Vite plagini (
@react-router/dev). Marshrutlarapp/routes.tsda fayllarga bog'lanadi, har fayl — route modul:defaultkomponent,loader/clientLoader,action,ErrorBoundary,meta.react-router typegenhar marshrut uchun turlarni o'zi yasaydi (Route.ComponentProps). Rejimlar: SSR (server HTML beradi), SPA (ssr: false) va prerender (HTML build paytida). Bu — Remix'ning davomi: Remix 2 React Router 7 ga birlashgan.
Bu darsda
- Framework mode data mode'dan nimasi bilan farq qilishini va u Remix bilan qanday bog'liqligini tushuntirasiz.
react-router.config.ts,app/root.tsx,app/routes.tsva route modul fayllarining vazifasini bilasiz.loadervaclientLoaderfarqini, typegen vahref()nima berishini ko'rasiz.- SSR, SPA va prerender rejimlarini taqqoslab, loyihaga mosini tanlay olasiz.
vazifalaruchun framework mode o'lchovini o'qiysiz va nega u kanonga kirmaganini tushuntira olasiz.
Oldin bilishingiz kerak: React Router IV: data mode — loader, action va xatolar, Vite II: vite.config, tsconfig frontend loyihada.
1. Nega bu kerak?
Oldingi darsda vazifalar ning vazifa sahifasi loader, action va errorElement oldi. Ishlayapti. Lekin Sardor uchta noqulaylikni sezdi:
- Marshrutlar fayli o'syapti.
marshrutlar.tsxda har sahifa uchun import,loader,action,errorElement— yigirma sahifada bu fayl ikki yuz qator bo'ladi. - Turlarni qo'lda bog'lash.
useLoaderData<typeof vazifaLoader>()— har safar loader nomini eslab yozish kerak. Unutsangiz,vazifa—unknown. - Birinchi kadr bo'sh. Brauzer avval bo'sh HTML oladi, keyin JS yuklanadi, keyin loader ishlaydi. Google va Telegram havola oldindan ko'rinishi uchun ham sahifa bo'sh.
React Router'ning uchinchi rejimi — framework mode — shu uchalasini hal qiladi. U data mode'ning ustiga quriladi: o'sha loader, action, <Form>. Faqat "qayerga nima yoziladi" ni konvensiya (kelishuv) belgilaydi va build vositasi qolgan ishni o'zi qiladi.
Hayotiy o'xshatish: data mode — o'zingiz yig'adigan mebel. Hamma detal bor, lekin har burama qayerga kirishini o'zingiz hal qilasiz. Framework mode — ustaxona: "eshik shu yerga, javon shu yerga" degan chizma tayyor. Erkinlik kamroq, lekin tezroq va xatosiz.
2. Remix'dan React Router 7 gacha
Framework mode'ning tarixi bor. Ko'p maqolada "Remix" nomi uchraydi — chalkashmaslik uchun qisqacha:
| Yil | Nima bo'ldi |
|---|---|
| 2021 | React Router mualliflari Remix frameworkini chiqardi: loader, action, <Form>, SSR |
| 2022 | React Router 6.4 — data mode: Remix'ning loader/action g'oyasi oddiy SPA'ga ham keldi |
| 2024, noyabr | React Router 7: Remix 2 ning imkoniyatlari framework mode sifatida React Router'ga birlashtirildi |
| 2026, iyun | React Router 8 — latest; framework mode — @react-router/dev 8 |
Demak, "Remix 2 loyiha" ni ko'rsangiz, uning davomi — bugungi framework mode. Importlar: @remix-run/react → react-router, @remix-run/dev → @react-router/dev. Chalkashtirmang: 2025-yil 28-mayda mualliflar "Remix" nomini Remix 3 uchun qayta ishlatishini e'lon qildi ("Wake up, Remix!", remix.run/blog). U React'ga bog'lanmagan, noldan qurilayotgan boshqa framework (Preact fork'idan boshlangan) — bu darsga aloqasiz.
3. Framework mode tuzilmasi
Kanon vazifalar ning o'sha sahifalarini (qobiq, ro'yxat, vazifa va 404) alohida tajriba loyihasida framework mode'da qurdi. Fayllar bo'yicha yuramiz — kodlar o'sha tajribadan aynan.
3.1 Paketlar va buyruqlar
package.json (tajriba, aynan):
{
"scripts": {
"build": "react-router build",
"tip": "react-router typegen && tsc"
},
"dependencies": {
"@react-router/dev": "8.4.0",
"react": "19.3.0",
"react-dom": "19.3.0",
"react-router": "8.4.0",
"isbot": "^5"
}
}@react-router/dev— Vite plagini vareact-routerbuyrug'i (CLI):react-router dev(dev server),react-router build,react-router typegen.isbot— SSR'da "bu so'rov qidiruv botidanmi?" ni aniqlaydi (botga sahifa to'liq tayyor holda beriladi).
Yangi loyiha noldan: npx create-react-router@latest. Lekin latest — kurs qoidasiga zid; versiyani @react-router/dev bilan bir xil qilib bering (Semver).
3.2 Ikki konfiguratsiya fayli
vite.config.ts — oddiy Vite, faqat plagin boshqa (aynan):
import { reactRouter } from "@react-router/dev/vite";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [reactRouter()],
});@vitejs/plugin-react o'rniga reactRouter(). U JSX'ni ham o'giradi, marshrutlarni ham o'qiydi.
react-router.config.ts — framework sozlamalari (aynan):
// 19/#06: framework mode — SPA (ssr: false): GitHub Pages kabi
// statik hosting uchun. Marshrutlar — app/routes.ts (fayl
// konfiguratsiyasi)
import type { Config } from "@react-router/dev/config";
export default {
ssr: false,
} satisfies Config;ssr: false — server yo'q, faqat statik fayllar. Sukut bo'yicha ssr: true. Rejimlar — «SSR, SPA va prerender» bo'limida. satisfies Config — satisfies darsidagi operator: obyekt turga mos ekanini tekshiradi, lekin turini kengaytirmaydi.
3.3 app/root.tsx — index.html o'rnida
Framework mode'da index.html yo'q. HTML'ning o'zi ham React komponenti (aynan):
// root.tsx — HTML qobig'i (framework mode'da index.html o'rniga)
import { Links, Meta, Outlet, Scripts } from "react-router";
import type { ReactNode } from "react";
export function Layout({ children }: { children: ReactNode }) {
return (
<html lang="uz">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<Meta />
<Links />
</head>
<body>
{children}
<Scripts />
</body>
</html>
);
}
export default function Ildiz() {
return <Outlet />;
}
export function HydrateFallback() {
return <p>Yuklanmoqda…</p>;
}<Meta />va<Links />— har sahifaningmetavalinkseksportlari shu yerga yig'iladi (sarlavha, tavsif, CSS).<Scripts />— ilovaning JS fayllari. Unutilsa, sahifa ko'rinadi, lekin hech bir tugma ishlamaydi.HydrateFallback— oldingi darsdagihydrateFallbackElementning o'zi, faqat eksport sifatida.
3.4 app/routes.ts — marshrutlar xaritasi
Data mode'dagi obyektlar massivi o'rniga — fayl yo'llari (aynan):
// Marshrutlar xaritasi (framework mode): data mode'dagi obyektlar
// o'rniga — fayllar. Kanondagi (marshrutlar.tsx) uch sahifa
import { index, layout, route } from "@react-router/dev/routes";
import type { RouteConfig } from "@react-router/dev/routes";
export default [
layout("routes/qobiq.tsx", [
index("routes/royxat.tsx"),
route("vazifa/:id", "routes/vazifa.tsx"),
route("*", "routes/topilmadi.tsx"),
]),
] satisfies RouteConfig;Har funksiya tanish narsaning qisqa yozuvi:
routes.ts |
Data mode'dagi |
|---|---|
route("vazifa/:id", fayl) |
{ path: "vazifa/:id", … } |
index(fayl) |
{ index: true, … } |
layout(fayl, [...]) |
yo'lsiz layout: { element, children } (03-dars) |
prefix("admin", [...]) |
bolalar yo'llari oldiga admin/ |
Faylning o'zi esa element, loader, action va boshqalarni beradi. Fayl nomidan marshrut yasaydigan variant ham bor — @react-router/fs-routes paketi (app/routes/vazifa.$id.tsx → /vazifa/:id). Lekin routes.ts — sukut bo'yicha va aniqroq yo'l.
3.5 Route modul — bitta faylda bitta sahifa
app/routes/vazifa.tsx (aynan):
// vazifa.tsx — /vazifa/:id: clientLoader (SPA'da loader — brauzerda).
// Route.* turlari — "react-router typegen" yasaydi: params.id —
// string, loaderData — clientLoader qaytargani
// (useLoaderData<typeof ...> shart emas)
import { data } from "react-router";
import type { Route } from "./+types/vazifa";
import { VAZIFALAR } from "./royxat.tsx";
export function clientLoader({ params }: Route.ClientLoaderArgs) {
const v = VAZIFALAR.find((x) => x.id === Number(params.id));
if (!v) throw data("yo'q", { status: 404 });
return v;
}
export default function Vazifa({ loaderData }: Route.ComponentProps) {
return <h2>{loaderData.matn}</h2>;
}Fayl nomlangan eksportlar orqali "men kimman" deydi. Router ularni nomidan taniydi:
| Eksport | Vazifasi |
|---|---|
default |
sahifa komponenti |
loader / action |
serverda ishlaydi (SSR yoki build paytida) |
clientLoader / clientAction |
brauzerda ishlaydi |
ErrorBoundary |
errorElement o'rni |
HydrateFallback |
birinchi ochilishdagi kutish |
meta, links |
<title>, tavsif, CSS havolalari |
handle, shouldRevalidate |
qo'shimcha ma'lumot, revalidatsiyani boshqarish |
Ikki yangilik bor. Birinchisi — loaderData endi prop: useLoaderData() hook'i ham ishlaydi, lekin prop qulayroq va turi tayyor. Ikkinchisi — import type { Route } from "./+types/vazifa". Bunday fayl papkada yo'q! Uni typegen yasaydi — «Typegen» bo'limida.
3.6 Route modul — aslida route obyekt
Sehr yo'q. Vite plagini route modulni data mode'dagi route obyektiga aylantiradi. Data mode ham obyektda komponentni element emas, komponent sifatida qabul qiladi: Component, ErrorBoundary, HydrateFallback kalitlari. Natija oynasida framework yo'q, lekin uning ishini qo'lda qilib ko'ramiz:
import {
createMemoryRouter,
data,
Link,
Outlet,
RouterProvider,
useLoaderData,
useRouteError,
} from "react-router";
const TASKS = [
{ id: 1, text: "Non olish" },
{ id: 2, text: "Sut olish" },
];
// "app/routes/vazifa.tsx" — route modul (eksportlar obyekti)
const taskModule = {
clientLoader({ params }) {
const task = TASKS.find((t) => t.id === Number(params.id));
if (!task) throw data("yo'q", { status: 404 });
return task;
},
default: function Task({ loaderData }) {
return <h2>{loaderData.text}</h2>;
},
ErrorBoundary() {
return <p>Vazifa topilmadi ({useRouteError().status})</p>;
},
};
// Plagin qiladigan ish: modul → route obyekt
function fromModule(path, mod) {
const Page = mod.default;
return {
path,
loader: mod.clientLoader,
ErrorBoundary: mod.ErrorBoundary,
// loaderData — prop sifatida
Component: () => <Page loaderData={useLoaderData()} />,
};
}
function Shell() {
return (
<div>
<Link to="/">Ro'yxat</Link>
<Outlet />
</div>
);
}
function List() {
return (
<p>
<Link to="/vazifa/2">Sut olish</Link>{" "}
<Link to="/vazifa/9">Choy olish</Link>
</p>
);
}
const router = createMemoryRouter([
{
Component: Shell,
children: [
{ index: true, Component: List },
fromModule("vazifa/:id", taskModule),
],
},
]);
export default function App() {
return <RouterProvider router={router} />;
}Ekranda:
Ro'yxat
Vazifa topilmadi (404)Uch o'tish: «Sut olish» — vazifa sahifasi, «Ro'yxat» — orqaga, «Choy olish» — /vazifa/9, bunday vazifa yo'q. Oxirgisida modulning ErrorBoundary si ishladi, Shell (yuqoridagi «Ro'yxat» havolasi) joyida qoldi.
fromModule — framework plaginining juda soddalashtirilgan nusxasi. Haqiqiysi ko'proq ish qiladi: har modulni alohida JS fayliga ajratadi (kod bo'lish), turlarni yasaydi, SSR'da loader ni serverga, clientLoader ni brauzerga yuboradi. Lekin mohiyat shu: framework mode = data mode + konvensiya + build.
Tekshirib ko'ring: Route modulda
export function loadervaexport function clientLoaderikkalasi ham bor. SPA rejimida (ssr: false) qaysi biri foydalanuvchi brauzerida ishlaydi?
Javob
clientLoader. Nomidagi client — "mijoz tomonda, brauzerda". loader esa server uchun: SSR rejimida har so'rovda serverda, SPA rejimida esa faqat prerender qilinadigan sahifalarda — build paytida, bir marta. Server yo'q joyda u ishlay olmaydi.
4. Typegen — turlar o'zi yoziladi
4.1 Route.ComponentProps qayerdan keladi?
react-router typegen buyrug'i routes.ts ni va har route modulni o'qiydi. Keyin .react-router/types/ papkasiga har marshrut uchun tur fayli yozadi. tsconfig.json dagi rootDirs uni ./+types/vazifa deb ko'rsatadi (tajriba, aynan):
{
"include": [
"app",
".react-router/types/**/*",
"react-router.config.ts",
"vite.config.ts"
],
"compilerOptions": {
"rootDirs": [".", "./.react-router/types"]
}
}Typegen nimani biladi:
vazifa/:idyo'lidan —params.idbor va ustring. Data mode'dauseParams()hamma kalitnistring | undefineddeb beradi, imlo xatosini (params.idd) ko'rmaydi.clientLoaderqaytarishidan —loaderDataturi{ id: number; matn: string }.routes.tsdagi hamma yo'llardan — qaysi manzillar mavjud.
dev buyrug'i ishlayotganda typegen fayl o'zgarganda o'zi yangilanadi. CI'da va tekshiruvdan oldin — react-router typegen && tsc (tajribadagi tip skripti). Kanon o'lchovi: tsc exit 0 (natijalar/tajriba/06-framework.txt).
4.2 href() — yo'l tekshiruvchi
Oxirgi bandning foydasi — href(). U yo'l shabloni va parametrlardan manzil yasaydi. app/routes/royxat.tsx da (aynan):
{/* href() — typegen'dan keyin yo'l va parametr nomi
tekshiriladi */}
<Link to={href("/vazifa/:id", { id: String(v.id) })}>
{v.matn}
</Link>href — oddiy funksiya, react-router dan; data mode'da ham bor. Natija oynasida:
import { href } from "react-router";
console.log(href("/vazifa/:id", { id: "2" }));
console.log(href("/taom/:slug?", {}));
console.log(href("/vazifa/:id", {}));
export default function App() {
return <p>Manzillar konsolda</p>;
}Konsolda:
/vazifa/2
/taom
Uncaught Error: Path '/vazifa/:id' requires param 'id' but it was not providedBirinchi ikki qator — tayyor manzillar. :slug? — ixtiyoriy segment (03-dars): berilmasa, tashlab ketiladi. Uchinchisi — xato: "/vazifa/:id yo'li id parametrini talab qiladi, lekin u berilmagan". Data mode'da bu xato faqat ishlaganda chiqadi — foydalanuvchi bosganda. Framework mode'da typegen href ga ro'yxatdagi yo'llar va ularning parametrlarini o'rgatadi: noto'g'ri yo'l yoki unutilgan parametr tsc da qizil bo'ladi, ilova build ham bo'lmaydi.
Maslahat: Shablon satr bilan yozilgan havola (
`/vazifa/${id}`) — har qanday satr./vazifalar/2deb xato yozsangiz, TypeScript indamaydi, sahifa 404 bo'ladi.href("/vazifa/:id", …)esa yo'l nomini ro'yxatdan tekshiradi. Bu yondashuvning eng to'liq ko'rinishi — TanStack Router darsida.
5. SSR, SPA va prerender
5.1 Uch yo'l — bitta kod
Framework mode'ning eng katta yangiligi — render qayerda bo'lishini tanlash. Kod bir xil, react-router.config.ts dagi ikki sozlama farq qiladi:
flowchart TB
B["Brauzer: /taom/osh"]
B --> SSR["SSR (ssr: true)<br/>server loader ishlaydi,<br/>tayyor HTML"]
B --> SPA["SPA (ssr: false)<br/>bo'sh index.html,<br/>brauzerda clientLoader"]
B --> PRE["Prerender<br/>HTML build paytida<br/>yasalgan, faylda"]
SSR --> H["Brauzer: hydration —<br/>HTML jonlanadi"]
SPA --> H2["Brauzer: hammasini<br/>JS chizadi"]
PRE --> HHar birini ochamiz:
- SSR (Server-Side Rendering) — har so'rovda server
loaderni ishlatadi va React'ni serverda chizib, tayyor HTML yuboradi. Brauzer matnni darhol ko'rsatadi, keyin JS kelib uni jonlantiradi — bu hydration (gidratatsiya) deyiladi: tayyor HTML'ga hodisalar ulanadi. Node server kerak. - SPA (
ssr: false) — biz qilib kelgan yo'l. Buildbuild/client/index.htmlyasaydi, hammasini brauzer chizadi. Har qanday statik hosting yetadi (GitHub Pages). - Prerender —
prerender: ["/", "/menyu"]sozlamasi. Ro'yxatdagi sahifalar build paytida bir marta chiziladi va HTML fayl bo'lib saqlanadi. Server kerak emas, lekin sahifa tayyor HTML bilan ochiladi.
| SSR | SPA | Prerender | |
|---|---|---|---|
| Birinchi kadr | tayyor matn | bo'sh, keyin JS | tayyor matn |
| Server | Node kerak | kerak emas | kerak emas |
| Ma'lumot yangiligi | har so'rovda | brauzerda | build paytidagi |
| Qachon | do'kon, yangiliklar | kabinet, panel | blog, hujjat, landing |
«Bahor» uchun aralash yechim ham mumkin: ssr: false va prerender: ["/", "/menyu"]. Menyu sahifasi Google uchun tayyor HTML, kabinet — oddiy SPA.
Diqqat: SSR'da komponent serverda ham chiziladi. U yerda
window,localStorage,documentyo'q. Render paytida ularga murojaat qilsangiz, serverReferenceErrorbilan yiqiladi. Brauzerga xos kod —useEffectichida yokiclientLoaderda. Shu tuzoqning Zustand'dagi ko'rinishi — Zustand II darsida.
5.2 Nega "bo'sh HTML" muhim?
Telegram'ga havola tashlasangiz, u sahifani yuklab, sarlavha va rasmni (Open Graph) oladi. JS'ni ishlatmaydi. SPA'da u faqat index.html dagi umumiy sarlavhani ko'radi: hamma taom havolasi bir xil ko'rinadi. SSR yoki prerender'da esa har sahifaning o'z meta si HTML'da bor. Google ham JS'ni ishlatadi, lekin kechroq va har doim emas.
vazifalar uchun bu muhim emas: shaxsiy ro'yxat qidiruvda chiqmasligi kerak. «Bahor» menyusi uchun — muhim. Tanlov loyihaning kimga ko'rinishiga bog'liq.
6. Kanon tajribasi: vazifalar framework mode'da
6.1 O'lchov
vazifalar ning o'sha uch sahifasi ikki variantda build qilindi: data mode (tajriba/variantlar/router-rr.tsx) va framework mode SPA (tajriba/framework/). Ikkalasida bir xil React 19.3.0, bir xil Vite 8.3.3:
- faqat React66,5 KB
- data mode1 fayl97,3 KB
- framework mode (SPA)12 fayl111,9 KB
Manba: O'lchandi: tajriba/qur.mjs va react-router build, gzip -9, natijalar/tajriba/hajm.txt va 06-framework.txt, 2026-10-14
Framework mode 14.6 KB katta va 12 faylga bo'lingan. Build chiqishidan (aynan, eng kattalari):
assets/entry.client-DUPmwnFo.js 214705 66336 57465
assets/errorBoundaries-D2FSGGX1.js 33515 11727 10610
assets/jsx-runtime-YqIuDQru.js 87379 28668 25419
assets/lib-DRLb-wQy.js 7252 2960 2623
assets/manifest-28b52888.js 2247 503 451
JAMI 347418 111884 97992 (12 fayl)Ustunlar: xom bayt, gzip, brotli. Qolgan yetti fayl — har route modul alohida (royxat, vazifa-client-loader, qobiq…), har biri 0.5 KB dan kichik. Plagin har marshrutni o'zi ajratdi — lazy ni qo'lda yozish shart emas. Lekin uch sahifali ilovada bu foyda bermaydi: hamma sahifa baribir kichik, fayllar soni esa ko'paydi. Typegen va tsc — toza: params.id ham, loaderData.matn ham turini o'zi oldi.
6.2 Nega kanonga kirmadi
QADAMLAR qarori (19/#06): framework mode vazifalar ga kirmadi. Sabablar:
- Hajm — +14.6 KB gzip, foydalanuvchi uchun hech narsa qo'shmasdan (SPA rejimi, SSR yo'q).
- Butun loyihani qayta tuzish.
index.html→root.tsx,main.tsx→ plagin, marshrutlar → fayllar, Vitest va 159 + 72 brauzer tekshiruvi — yangi tuzilmaga. Ishlab turgan, tekshirilgan kodni ko'chirish xavfi foydadan katta. - SSR'siz asosiy foyda — faqat tiplar. GitHub Pages'da server yo'q,
vazifalarqidiruvda ham kerak emas.
Bu framework mode'ni kamsitish emas. Yangi loyiha boshlasangiz va unda ochiq sahifalar (do'kon, menyu, blog) bo'lsa — framework mode yaxshi tanlov: SSR yoki prerender, avtomatik kod bo'lish va turlar bir paketda. Xuddi shu g'oyalarni Next.js qismida ham ko'rasiz: fayl asosidagi marshrutlar, server loader, SSR. Bugungi dars o'sha qismga ko'prik.
7. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
Cannot find module './+types/vazifa' |
typegen ishlamagan | react-router typegen (yoki dev ni yoqing), tsconfig da rootDirs |
| sahifa ko'rinadi, tugmalar ishlamaydi | root.tsx da <Scripts /> yo'q |
<body> oxiriga <Scripts /> |
window is not defined (SSR) |
render paytida brauzer obyekti | useEffect yoki clientLoader ga ko'chiring |
loader SPA'da ishlamaydi |
ssr: false, server yo'q |
clientLoader |
@remix-run/react topilmadi |
eski Remix kodi | react-router dan import |
| server va brauzer HTML'i farq qiladi (hydration xatosi) | renderda Date.now(), Math.random() |
qiymatni effektda yoki loader'da hisoblang |
8. Mashqlar
Mashqlar kurs/mashqlar/19/06-framework-mode/ da. Har yechimni «Ishga tushir» bilan sinang.
1-mashq (oson): qaysi fayl?
Bo'sh joylarni to'ldiring (fayl nomi bilan):
ssr: falsesozlamasi — faylida.<html>,<head>va<Scripts />— faylida.route("vazifa/:id", "routes/vazifa.tsx")— faylida.export function clientLoader— faylida.
Yechim
react-router.config.ts — butun framework sozlamasi (rejim, prerender). app/root.tsx — HTML qobig'i, index.html o'rni. app/routes.ts — qaysi yo'lga qaysi fayl. app/routes/vazifa.tsx — route modul: sahifaning komponenti, loader'i va xato chegarasi bir joyda. Bu bo'linish — konvensiya: boshqa framework mode loyihasini ochsangiz, aynan shu fayllarni qidirasiz.
2-mashq (o'rta): modulni ulang
Quyidagi menuModule — route modul. Uni fromModule yordamchisi bilan /menyu marshrutiga ulang. fromModule ga HydrateFallback ni ham qo'shing (modulda bor). Boshlang'ich kod hozir faqat "Bosh sahifa" ni ko'rsatadi; «Menyu» havolasi 404 ga olib boradi.
Ishora: «Route modul — aslida route obyekt» bo'limi.
import {
createMemoryRouter,
Link,
RouterProvider,
useLoaderData,
} from "react-router";
const wait = (ms, value) =>
new Promise((resolve) => setTimeout(() => resolve(value), ms));
const menuModule = {
clientLoader: () => wait(200, ["Osh", "Manti", "Lag'mon"]),
default: function Menu({ loaderData }) {
return <p>Menyu: {loaderData.join(", ")}</p>;
},
HydrateFallback: () => <p>Menyu yuklanmoqda…</p>,
};
function fromModule(path, mod) {
const Page = mod.default;
return {
path,
loader: mod.clientLoader,
Component: () => <Page loaderData={useLoaderData()} />,
};
}
const router = createMemoryRouter([
{ path: "/", element: <Link to="/menyu">Menyu</Link> },
{ path: "*", element: <p>404</p> },
]);
export default function App() {
return <RouterProvider router={router} />;
}Ekranda:
404Yechim
import {
createMemoryRouter,
Link,
RouterProvider,
useLoaderData,
} from "react-router";
const wait = (ms, value) =>
new Promise((resolve) => setTimeout(() => resolve(value), ms));
const menuModule = {
clientLoader: () => wait(200, ["Osh", "Manti", "Lag'mon"]),
default: function Menu({ loaderData }) {
return <p>Menyu: {loaderData.join(", ")}</p>;
},
HydrateFallback: () => <p>Menyu yuklanmoqda…</p>,
};
function fromModule(path, mod) {
const Page = mod.default;
return {
path,
loader: mod.clientLoader,
HydrateFallback: mod.HydrateFallback,
Component: () => <Page loaderData={useLoaderData()} />,
};
}
const router = createMemoryRouter([
{ path: "/", element: <Link to="/menyu">Menyu</Link> },
fromModule("/menyu", menuModule),
{ path: "*", element: <p>404</p> },
]);
export default function App() {
return <RouterProvider router={router} />;
}Ekranda:
Menyu: Osh, Manti, Lag'monfromModule("/menyu", menuModule) — massivdagi oddiy route obyekt, * dan oldin ham, keyin ham ishlaydi (router eng aniq mosini tanlaydi — 03-dars). HydrateFallback bu yerda ko'rinmaydi: ilova / dan boshlandi, menyuga o'tishda router eski sahifani ushlab turadi. U /menyu to'g'ridan ochilganda kerak — initialEntries: ["/menyu"] bilan sinab ko'ring.
3-mashq (qiyin): o'z routes.ts ingiz
Framework'dagi route, index va layout funksiyalarini o'zingiz yozing. Ular komponent oladi (fayl o'rniga) va data mode route obyektini qaytaradi:
route(path, Component, children?)→{ path, Component, children }index(Component)→{ index: true, Component }layout(Component, children)→{ Component, children }
Boshlang'ich kodda routes massivi tayyor. Hozir u ReferenceError: layout is not defined bilan yiqiladi. Uchala funksiyani yozsangiz, ilova ishlaydi.
import {
createMemoryRouter,
Link,
Outlet,
RouterProvider,
} from "react-router";
// route, index, layout — shu yerga
const Shell = () => (
<div>
<Link to="/">Bosh</Link> <Link to="/aloqa">Aloqa</Link>
<Outlet />
</div>
);
const Home = () => <p>«Bahor» oshxonasi</p>;
const Contact = () => <p>Tel: +998 90 000 00 00</p>;
const routes = [
layout(Shell, [index(Home), route("aloqa", Contact)]),
];
const router = createMemoryRouter(routes);
export default function App() {
return <RouterProvider router={router} />;
}Yechim
import {
createMemoryRouter,
Link,
Outlet,
RouterProvider,
} from "react-router";
const route = (path, Component, children) => ({
path,
Component,
children,
});
const index = (Component) => ({ index: true, Component });
const layout = (Component, children) => ({ Component, children });
const Shell = () => (
<div>
<Link to="/">Bosh</Link> <Link to="/aloqa">Aloqa</Link>
<Outlet />
</div>
);
const Home = () => <p>«Bahor» oshxonasi</p>;
const Contact = () => <p>Tel: +998 90 000 00 00</p>;
const routes = [
layout(Shell, [index(Home), route("aloqa", Contact)]),
];
const router = createMemoryRouter(routes);
export default function App() {
return <RouterProvider router={router} />;
}Ekranda:
Bosh Aloqa
Tel: +998 90 000 00 00Uchala funksiya — bir qatorli obyekt yasovchilar. routes.ts ning haqiqiy funksiyalari ham deyarli shunday: ular fayl yo'lini saqlaydi, komponentni esa plagin build paytida o'sha fayldan oladi. E'tibor bering: layout da path yo'q — yo'lsiz layout. Oxirgi narsa: route da children ixtiyoriy: berilmasa undefined — router uni "bolasi yo'q" deb tushunadi.
4-mashq: vazifalar ga nazar
Bu darsda vazifalar o'zgarmaydi. Darsdagi tajriba fayllarini («Route modul — bitta faylda bitta sahifa» va «app/routes.ts») data mode darsidagi vazifa-marshruti.ts bilan solishtiring. Ikki savolga javob yozing: (1) data mode'dagi vazifaLoader framework'da qaysi faylda va qaysi nomda? (2) Nega vazifa.tsx da useLoaderData<typeof …> yo'q?
Yechim
(1) app/routes/vazifa.tsx da, clientLoader nomida: SPA rejimida server yo'q, loader brauzerda ishlaydi. Data mode'da u marshrutlar massivida loader: vazifaLoader edi. (2) Komponent loaderData ni prop sifatida oladi va uning turi — Route.ComponentProps dan: typegen uni clientLoader ning qaytish turidan yasagan. Qo'lda typeof yozish shart emas — loader o'zgarsa, tur ham o'zi o'zgaradi.
9. Real ishda
- Shopify — 2022-yilda Remix jamoasini qo'shib olgan. Uning do'kon frameworki Hydrogen 2025.5.0 (2025-yil may) dan Remix 2 o'rniga React Router 7 framework mode ustida.
- Yangi React loyiha tanlovi — React hujjati (react.dev) yangi ilova uchun framework tavsiya qiladi: Next.js yoki React Router framework mode. Ikkalasi ham loader/server g'oyasida.
- Migratsiya — "Remix 2 → React Router 7" eng ko'p uchraydigan ish: importlarni almashtirish,
vite.configdagi plagin. Data mode'dan framework'ga ham bosqichma-bosqich o'tish mumkin — har marshrutni alohida. - Intervyu savollari: "SSR, SPA va SSG (prerender) farqi?", "hydration nima?", "
loadervaclientLoaderqachon?", "Remix va React Router qanday bog'liq?".
Xulosa
- Framework mode = data mode + Vite plagini (
@react-router/dev) + konvensiya. Remix 2 shu nom bilan React Router 7 ga birlashgan. - Fayllar:
react-router.config.ts(rejim),app/root.tsx(HTML qobig'i),app/routes.ts(route,index,layout,prefix), route modullar. - Route modul eksportlari:
default,loader/clientLoader,action,ErrorBoundary,HydrateFallback,meta.loaderData— prop. - Typegen
Route.*turlarini yasaydi;href()yo'l va parametrni tekshiradi. - SSR — har so'rovda serverda, SPA — brauzerda, prerender — build paytida. Tanlov — sahifa kimga ko'rinishiga bog'liq.
vazifalarda o'lchandi: 111.9 vs 97.3 KB, 12 fayl; SSR'siz foyda faqat tiplar — kanonga kirmadi.
Keyingi dars: Himoyalangan marshrutlar va rolga asoslangan kirish — kirmagan foydalanuvchini kirish sahifasiga yuborish, ?keyin= bilan qaytarish va "miltillash" siz himoya.
Manbalar
- React Router: Framework Mode — reactrouter.com/start/framework/installation, routing, route-module, rendering (2026-10 holatiga, v8.4.0)
- React Router: Type Safety (typegen,
href) — reactrouter.com/explanation/type-safety - React Router: SPA Mode, Pre-Rendering — reactrouter.com/how-to/spa, /how-to/pre-rendering
- Remix blog: "Merging Remix and React Router" (2024), "Wake up, Remix!" (2025-05-28) — remix.run/blog
- Shopify: "Hydrogen May 2025 release" (2025.5.0 — React Router 7) — hydrogen.shopify.dev/update/may-2025
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!