13.2-bob: App Router va file-based routing
13-QISM — Next.js · 2-mavzu
1. Kirish va motivatsiya
13.1-bobda Next.js'ning fayl-asosli routing'i bilan tanishdik — app/products/page.tsx avtomatik /products bo'ladi. Endi shu routing'ni chuqur o'rganamiz: dinamik yo'llar (/products/42 — har mahsulot uchun), nested layouts (har bo'lim o'z karkasi), route groups (URL'ni o'zgartirmasdan fayllarni guruhlash), navigatsiya (<Link>, useRouter, redirect), va maxsus fayllar (loading, error, not-found). Bu — Next.js ilovasining skeletini tashkil qiladi, va u React Router'dan 11.9-bob ancha kuchliroq va deklarativroq.
App Router'ning markaziy g'oyasi — konvensiya orqali routing (configuration over convention'ning teskarisi): siz routing'ni kod bilan sozlamaysiz (React Router'dagi <Routes>, <Route> massivlari — 11.9 — yo'q), balki papka va fayl strukturasi routing'ni belgilaydi. app/ papkacidagi har papka — URL segmenti, har page.tsx — sahifa, har layout.tsx — o'rovchi. Bu juda kuchli: routing "jonli xarita" bo'ladi (papkani ko'rib URL'ni bilasiz), nested layout tabiiy (papka ichida papka), va maxsus fayllar (loading/error) avtomatik ishlaydi. Bundan tashqari, App Router Server Components bilan ishlaydi (default — 13.3), shuning uchun routing va ma'lumot olish chambarchas bog'liq.
Bu bob: fayl-asosli routing (page/folder — chuqur), dinamik segmentlar ([id], [...slug] — catch-all, [[...slug]] — optional), params (sahifa dinamik qiymatni qanday oladi), nested layouts (ko'p qatlamli — har bo'lim o'z layout'i), route groups ((group) — URL'siz guruhlash), private papkalar (_folder), navigatsiya (<Link>, useRouter, redirect, usePathname), maxsus fayllar (loading/error/not-found — konvensiya), parallel/intercepting routes (ilg'or — qisqa), va generateStaticParams (dinamik SSG — 13.4 ko'prik). Har bir mavzu to'liq, har kod misolida maqsad + izoh + "nima qiladi" bilan ochiladi.
O'xshatish: App Router — bu bino qavatlar rejasi (blueprint). React Router 11.9-bob — bu qo'lda yozilgan manzillar ro'yxati (
/products ProductPage,/about AboutPage— har birini qog'ozga yozasiz). App Router — bu binoning o'zi qavatlar rejasi: har xona (papka) o'z manziliga ega (URL), xona ichidagi "asosiy jihoz" (page.tsx) — o'sha xonaning mazmuni, va har qavat (papka) o'z umumiy koridori va lift'iga (layout.tsx) ega bo'lishi mumkin. Siz alohida manzillar ro'yxatini saqlamaysiz — bino strukturasining o'zi manzilni belgilaydi (4-qavat, 12-xona =/floor4/room12). Yangi xona qo'shsangiz — yangi manzil avtomatik paydo bo'ladi. Bu — "kod o'rniga struktura" falsafasi.
Nega muhim?
- Next.js skeleti — routing har Next.js ilovasining asosi (sahifalar, layout, navigatsiya).
- Deklarativ va kuchli — fayl strukturasi routing (React Router kodidan ancha sodda va aniq).
- Nested layouts — murakkab ilova strukturasi (dashboard, ko'p bo'lim) tabiiy.
- Server Components bilan — routing + ma'lumot olish integratsiyalangan (13.3, 13.5).
2. Nazariya — chuqur tushuntirish
2.1. Fayl-asosli routing (chuqur)
PAPKA STRUKTURASI = URL (App Router — har papka segmenti, page.tsx = sahifa):
app/
├── page.tsx / (bosh sahifa)
├── about/page.tsx /about
├── products/
│ ├── page.tsx /products (mahsulotlar ro'yxati)
│ └── [id]/page.tsx /products/42 (dinamik — har mahsulot — 2.2)
├── blog/
│ ├── page.tsx /blog
│ └── [slug]/page.tsx /blog/my-post
└── dashboard/
├── layout.tsx dashboard layout (faqat /dashboard/* uchun — 2.4)
├── page.tsx /dashboard
└── settings/page.tsx /dashboard/settings
ASOSIY QOIDA:
- PAPKA URL segmenti (products /products)
- page.tsx sahifa (route'ni "ko'rinadigan" qiladi — page.tsx YO'Q bo'lsa URL ishlamaydi)
- boshqa fayllar (Button.tsx) route EMAS (faqat page.tsx route bo'ladi)
Papka = URL; page.tsx = sahifa (boshqa .tsx fayllar route'ga aylanmaydi — xavfsiz)
page.tsx YO'Q bo'lsa — papka URL sifatida ishlamaydi (faqat tashkilot)Fayl-asosli routing — App Router'ning poydevori. Papka strukturasi URL'ni belgilaydi:
app/ichidagi har papka — URL segmenti (products/products), va har papkadagipage.tsx— o'sha yo'lning sahifasi. Misol:app/products/page.tsx/products,app/dashboard/settings/page.tsx/dashboard/settings(papka ichma-ich URL ichma-ich). Asosiy qoida: papka URL segmenti,page.tsxsahifa (route'ni "ko'rinadigan" qiladi). Ikki muhim nuqta: (1) faqatpage.tsx(aniq shu nom) route'ga aylanadi — papkadagi boshqa fayllar (Button.tsx,utils.ts) route emas (ular faqat tashkilot/yordamchi — bu xavfsizlik: tasodifan komponent fayli URL bo'lib qolmaydi — React Router'dan farqli, u yerda har narsa qo'lda yoziladi); (2)page.tsxyo'q bo'lsa — papka URL sifatida ishlamaydi (faqat fayllarni guruhlash — masalanapp/products/components/papkasidapage.tsxyo'q u URL emas, faqat komponentlar uchun papka). Bu — fayl-routing'ning asosi: papka = yo'l,page.tsx= sahifa, qolgani = tashkilot.
2.2. Dinamik segmentlar — [id], [...slug]
DINAMIK SEGMENT — URL'ning O'ZGARUVCHAN qismi (kvadrat qavs []):
[id] bitta dinamik segment: app/products/[id]/page.tsx /products/42, /products/abc
[...slug] catch-all (ko'p segment): app/docs/[...slug]/page.tsx /docs/a, /docs/a/b/c
[[...slug]] optional catch-all: app/shop/[[...slug]]/page.tsx /shop, /shop/a, /shop/a/b
KOMPONENT params'ni oladi (Server Component — props orqali):
// app/products/[id]/page.tsx
export default async function ProductPage({ params }) {
const { id } = await params; // Next.js 15: params async
return <h1>Mahsulot {id}</h1>; // /products/42 id = "42"
}
┌────────────────────────────────────────────────────────────┐
│ [id]: /products/42 (bitta) | [...slug]: /docs/a/b (ko'p) │
│ [[...slug]]: optional (/shop yoki /shop/a) | params: qiymat │
└────────────────────────────────────────────────────────────┘
[id] — bitta segment; [...slug] — ko'p (massiv); [[...slug]] — ixtiyoriy ko'p
params — sahifaga dinamik qiymatni beradi (Next.js 15: async — await params)Dinamik segmentlar — URL'ning o'zgaruvchan qismlari (kvadrat qavs
[]bilan). Uch tur: (1)[id]— bitta dinamik segment:app/products/[id]/page.tsx/products/42,/products/abc(har mahsulot uchun bitta sahifa — 11.9: 2.6 React Router'ning:idiga o'xshaydi); (2)[...slug]— catch-all (ko'p segment):app/docs/[...slug]/page.tsx/docs/a,/docs/a/b/c(slugmassiv bo'ladi —["a", "b", "c"]— docs/wiki kabi ko'p qatlamli yo'l uchun); (3)[[...slug]]— optional catch-all:app/shop/[[...slug]]/page.tsx/shopva/shop/a/b(segment bo'lmasa ham ishlaydi — ixtiyoriy). Komponent dinamik qiymatniparamsprop orqali oladi (Server Component):export default async function ProductPage({ params }) { const { id } = await params; ... }— Next.js 15'daparamsasync (await params— chunki so'rov ma'lumotlari async — 13.1: 2.10). Ikki nuqta: (1)[id]— bitta segment,[...slug]— ko'p (massiv),[[...slug]]— ixtiyoriy ko'p; (2)params— sahifaga dinamik qiymatni beradi (Next.js 15:await params). Bu — bitta sahifa bilan cheksiz kontent (mahsulot, blog post, foydalanuvchi profili) yaratishning asosi.
2.3. Nested layouts — ko'p qatlamli
NESTED LAYOUTS — har papkada O'Z layout'i (ichma-ich o'raydi — kuchli):
app/
├── layout.tsx ILDIZ layout (BARCHA sahifani o'raydi — <html><body>)
└── dashboard/
├── layout.tsx dashboard layout (FAQAT /dashboard/* uchun)
├── page.tsx /dashboard
└── settings/page.tsx /dashboard/settings
/dashboard/settings ochilganda — layoutlar ICHMA-ICH o'raydi:
┌─ RootLayout (html/body, navbar) ──────────────┐
│ ┌─ DashboardLayout (sidebar) ──────────────┐ │
│ │ ┌─ SettingsPage (kontent) ───────────┐ │ │
│ │ │ Sozlamalar │ │ │
│ │ └─────────────────────────────────────┘ │ │
│ └────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────┐
│ Layout'lar ichma-ich (root > dashboard > sahifa) │
│ Layout — navigatsiyada SAQLANADI (qayta render bo'lmaydi) │
└────────────────────────────────────────────────────────────┘
Har papka o'z layout.tsx'iga ega bo'lishi mumkin (ichma-ich o'raydi)
Layout navigatsiyada saqlanadi (sidebar — /dashboard ichida sahifa almashca qayta render yo'q)Nested layouts — App Router'ning eng kuchli xususiyatlaridan biri. Har papka o'z **
layout.tsx**iga ega bo'lishi mumkin, va layoutlar ichma-ich o'raydi. Misol:app/layout.tsx(root —<html>/<body>, umumiy navbar — har sahifani o'raydi) +app/dashboard/layout.tsx(dashboard layout — sidebar — faqat/dashboard/*sahifalari uchun)./dashboard/settingsochilganda, layoutlar ichma-ich o'raydi: RootLayout (navbar) DashboardLayout (sidebar) SettingsPage (kontent) — har biri o'z bo'lagini beradi. (Diqqat: bola sahifa layout'gachildrenprop orqali keladi.) Bu React Router'ning nested routes + Outlet'iga (11.9: 2.7) o'xshaydi, lekin Next.js'da fayl strukturasi orqali (qo'lda<Outlet>joylashtirish kerak emas —layout.tsxavtomatik bola sahifanichildrenorqali oladi). Ikki muhim nuqta: (1) har papka o'zlayout.tsxiga ega bo'lishi mumkin (ko'p qatlamli — dashboard, marketing, admin — har biri o'z karkasi); (2) layout navigatsiyada saqlanadi —/dashboardichida sahifalar almashganda (settings analytics), DashboardLayout (sidebar) qayta render bo'lmaydi (faqat kontent o'zgaradi — performance, va sidebar state saqlanadi). Bu — murakkab ilova strukturasini (ko'p bo'limli dashboard) tabiiy va samarali qiladi.
2.4. Route groups — (group)
ROUTE GROUP — fayllarni guruhlash, lekin URL'ni O'ZGARTIRMASDAN (qavs () bilan):
app/
├── (marketing)/ qavs () — URL'da KO'RINMAYDI (faqat tashkilot)
│ ├── layout.tsx marketing layout (faqat shu guruh)
│ ├── page.tsx / (NOT /marketing — qavs URL'da yo'q!)
│ └── about/page.tsx /about (NOT /marketing/about)
└── (shop)/
├── layout.tsx shop layout (boshqa layout)
├── products/page.tsx /products
└── cart/page.tsx /cart
NEGA ROUTE GROUP:
Turli LAYOUT'lar (marketing sahifalar bir layout, shop boshqa — URL'siz)
Fayllarni mantiqiy guruhlash (URL'ni o'zgartirmasdan)
┌────────────────────────────────────────────────────────────┐
│ (group): papka URL'da YO'Q (faqat tashkilot/layout) │
│ /about (NOT /marketing/about) — guruhlash URL'ni o'zgartirmaydi│
└────────────────────────────────────────────────────────────┘
(group) — qavs ichidagi papka URL'ga KIRMAYDI (faqat tashkilot + layout)
Turli bo'limga turli layout berish uchun (marketing/shop/auth — har biri o'z layout)Route groups — App Router'ning nozik, lekin foydali imkoniyati. Route group — papkani qavs
()bilan o'rab, fayllarni guruhlash, lekin URL'ni o'zgartirmaslik. Misol:app/(marketing)/about/page.tsxURL/about(NOT/marketing/about—(marketing)URL'da ko'rinmaydi, faqat tashkilot). Nega route group kerak: (1) turli layout'lar — masalan marketing sahifalari (bosh, about) bitta layout (oddiy navbar), shop sahifalari (products, cart) boshqa layout (savat ikonkasi bilan) —(marketing)/layout.tsxva(shop)/layout.tsx— lekin URL'lar bir xil darajada (/about,/products— guruh nomi URL'da yo'q); (2) fayllarni mantiqiy guruhlash (URL'ni o'zgartirmasdan — toza tashkilot). Ikki nuqta: (1)(group)— qavs ichidagi papka URL'ga kirmaydi (faqat tashkilot va layout uchun); (2) bu turli bo'limga (marketing/shop/auth — har biri o'z layout va navbar'iga ega, lekin URL'lar bir darajada) turli layout berishning toza usuli. Masalan(auth)/login,(auth)/register— login/register oddiy markazlashgan layout (sidebar yo'q), qolgan sahifalar to'liq layout — URL/login,/register(auth so'zi yo'q). Bu — fayl tashkiloti va layoutni URL'dan ajratish imkonini beradi (moslashuvchanlik).
2.5. Maxsus fayllar — loading, error, not-found
MAXSUS FAYLLAR (App Router konvensiyasi — har biri aniq vazifa):
page.tsx sahifa (route)
layout.tsx o'rovchi layout 2.3-bob
loading.tsx yuklanish UI (Suspense AVTOMATIK — 13.1: Misol 7)
error.tsx xato UI (error boundary AVTOMATIK — "use client" majburiy)
not-found.tsx 404 sahifa
template.tsx layout kabi, lekin HAR navigatsiyada qayta render (kam — 2.10)
HAR PAPKADA bo'lishi mumkin (segment darajasida):
app/dashboard/loading.tsx faqat /dashboard yuklanishda
app/dashboard/error.tsx faqat /dashboard xatosida (boshqa bo'limga ta'sir yo'q)
┌────────────────────────────────────────────────────────────┐
│ loading.tsx: Suspense | error.tsx: error boundary 11.12-bob │
│ not-found.tsx: 404 | — har papkada (segment darajasida) │
└────────────────────────────────────────────────────────────┘
Maxsus fayl nomlari — Next.js konvensiyasi (loading/error/not-found avtomatik ishlaydi)
Har papkada bo'lishi mumkin (granular — faqat o'sha bo'lim uchun — 11.12: 2.4 kabi)Maxsus fayllar — App Router'ning konvensiya-asosli imkoniyatlari (11.8 Suspense va 11.12 error boundary'ni avtomatik qiladi). Asosiy maxsus fayllar (har biri aniq vazifaga ega):
page.tsx(sahifa),layout.tsx(o'rovchi — 2.3),loading.tsx(yuklanish UI — Next.js avtomatik Suspense o'raydi — 13.1: Misol 7),error.tsx(xato UI — avtomatik error boundary;"use client"majburiy — chunki error boundary client'da ishlaydi — 11.12),not-found.tsx(404 sahifa),template.tsx(layout kabi, lekin har navigatsiyada qayta render — kam ishlatiladi — 2.10). Eng muhim — bular har papkada (segment darajasida) bo'lishi mumkin:app/dashboard/loading.tsx— faqat/dashboardyuklanishda;app/dashboard/error.tsx— faqat/dashboardxatosida (boshqa bo'limga ta'sir qilmaydi — granular — 11.12: 2.4). Ikki nuqta: (1) maxsus fayl nomlari — Next.js konvensiyasi (sizloading.tsx/error.tsxyaratasangiz, Next.js avtomatik Suspense/error boundary'ni qo'shadi — qo'lda o'rash kerak emas); (2) har papkada bo'lishi mumkin (granular izolyatsiya — bir bo'lim xatosi butun ilovani buzmaydi — 11.12: 2.4). Bu — robust, foydalanuvchiga g'amxo'r UI'ning avtomatik infratuzilmasi.
2.6. Navigatsiya — Link va useRouter
IKKI NAVIGATSIYA USULI:
1. <Link> — DEKLARATIV (foydalanuvchi bosadigan havola — 13.1: Misol 4):
import Link from "next/link";
<Link href="/products">Mahsulotlar</Link> // prefetch avtomatik
2. useRouter — DASTURIY (kod orqali — Client Component'da — "use client"):
"use client";
import { useRouter } from "next/navigation"; // next/navigation (next/router EMAS — eski)
const router = useRouter();
router.push("/dashboard"); // o'sha sahifaga
router.replace("/login"); // tarixni almashtir (orqaga qaytmasin)
router.back(); // orqaga
router.refresh(); // joriy sahifani server'dan qayta yukla
SERVER'DA (Server Component/Action) — redirect:
import { redirect, permanentRedirect } from "next/navigation";
redirect("/login"); // server'da yo'naltirish (307/302 — vaqtinchalik)
permanentRedirect("/new-url"); // doimiy yo'naltirish (308/301 — SEO, ko'chirilgan sahifa)
<Link> — bosiladigan navigatsiya; useRouter — kod (hodisa/shart) — client'da
redirect — server'da (Server Component/Action — 13.5); next/navigation'dan (yangi)Navigatsiya — Link va useRouter — Next.js'da sahifalar orasida o'tishning uch usuli (React Router'ning — 11.9 — Next.js versiyalari). (1)
<Link>— deklarativ (foydalanuvchi bosadigan havola — 13.1: Misol 4):<Link href="/products">— client-side navigatsiya + avtomatik prefetch. (2)useRouter— dasturiy (kod orqali — Client Component'da,"use client"kerak):const router = useRouter()(next/navigation'dan — diqqat:next/router— eski Pages Router'niki — App Router'danext/navigation), keyinrouter.push("/dashboard")(o'sha sahifaga),router.replace("/login")(tarixni almashtirib — orqaga qaytmasin — 11.9: 2.9),router.back()(orqaga),router.refresh()(joriy sahifani server'dan qayta yukla — ma'lumot yangilangan bo'lsa). (3)redirect— server'da (Server Component yoki Server Action — 13.5):redirect("/login")(next/navigation'dan — server'da yo'naltirish, masalan auth tekshiruvida — vaqtinchalik, 307/302). Doimiy ko'chirish uchun esapermanentRedirect("/new-url")(308/301 — sahifa butunlay ko'chirilganda, SEO'ga to'g'ri signal). Ikki nuqta: (1)<Link>— bosiladigan navigatsiya;useRouter— kod (hodisa/shart natijasida — login'dan keyin) — client'da;redirect— server'da; (2)next/navigation(App Router) —next/router(Pages Router — eski) emas (bu keng xato). Bu uch usul — interaktiv oqimlar (login, forma submit, shartli yo'naltirish)ni qoplaydi.
2.7. usePathname va useSearchParams
JORIY URL HAQIDA MA'LUMOT (Client Component'da — "use client"):
usePathname — joriy YO'L (path):
"use client";
import { usePathname } from "next/navigation";
const pathname = usePathname(); // "/products" (active link uchun)
useSearchParams — query string (?filter=...):
import { useSearchParams } from "next/navigation";
const searchParams = useSearchParams();
const category = searchParams.get("category"); // ?category=phone "phone"
ACTIVE LINK (joriy sahifani ajratish — navbar):
const pathname = usePathname();
<Link href="/products" className={pathname === "/products" ? "active" : ""}>...</Link>
┌────────────────────────────────────────────────────────────┐
│ usePathname: joriy yo'l (/products) | useSearchParams: query │
│ (Client Component — "use client"; React Router'ning o'xshashi)│
└────────────────────────────────────────────────────────────┘
usePathname/useSearchParams — Client Component'da (joriy URL — active link, filtr)
Server Component — params/searchParams PROPS orqali (hook emas — 13.5)usePathname va useSearchParams — joriy URL haqida ma'lumot olish (Client Component'da).
usePathname— joriy yo'lni qaytaradi (const pathname = usePathname()"/products") — odatda active link uchun (navbar'da joriy sahifani ajratish — 11.9: 2.5 NavLink'ning Next.js usuli).useSearchParams— query string'ni o'qish (const searchParams = useSearchParams(); searchParams.get("category")?category=phone"phone") — filtr, sahifalash holati uchun (11.9: 2.10 React Router'ninguseSearchParamsiga o'xshaydi). Active link misol:usePathname()bilan joriy yo'lni olib,<Link className={pathname === "/products" ? "active" : ""}>(joriy sahifa havolasini ajratish). Ikki muhim nuqta: (1)usePathname/useSearchParams— Client Component'da ("use client"— bular hook, brauzerda ishlaydi); (2) Server Component'da esaparamsvasearchParamsprops orqali olinadi (hook emas — sahifaga props sifatida beriladi — 13.5):export default function Page({ searchParams }) {...}. Bu farqni tushunish muhim — server'da props, client'da hook. Active link va filtr — bu hooklarning asosiy ishlatilishi.
2.8. generateStaticParams (dinamik SSG — 13.4 ko'prik)
MUAMMO: dinamik sahifa ([id]) — qaysi id'lar BUILD paytida statik (SSG — 13.4) generatsiya?
generateStaticParams — dinamik yo'llar uchun statik params (oldindan generatsiya):
// app/products/[id]/page.tsx
export async function generateStaticParams() {
const products = await fetch("/api/products").then((r) => r.json());
return products.map((p) => ({ id: p.id })); // har id uchun statik sahifa (build'da)
}
// build paytida /products/1, /products/2, ... STATIK HTML generatsiya (SSG — tez)
NEGA:
Dinamik yo'l ([id]) + statik tezlik (build'da oldindan — SSG — 13.4)
Blog post, mahsulot — ma'lum, o'zgarmaydigan statik (eng tez)
┌────────────────────────────────────────────────────────────┐
│ generateStaticParams: [id] yo'llar uchun statik sahifalar │
│ (build'da /products/1, /products/2... — SSG tezlik — 13.4) │
└────────────────────────────────────────────────────────────┘
generateStaticParams — dinamik [id] yo'llarni build'da statik qiladi (SSG — 13.4)
Blog/mahsulot (ma'lum, o'zgarmas) statik (tez); 13.4'da rendering chuqurgenerateStaticParams — dinamik yo'llarni statik (SSG) qilishning usuli (13.4 rendering bilan ko'prik). Muammo: dinamik sahifa (
[id]) — Next.js qanday qilib build paytida statik HTML generatsiya qiladi (SSG — eng tez — 13.4)? Qaysiidlar uchun? Javob —generateStaticParams:export async function generateStaticParams() { const products = await fetch(...); return products.map((p) => ({ id: p.id })) }— bu funksiya build paytida ishlaydi va qaysiidlar uchun statik sahifa generatsiya qilishni aytadi (har mahsulot id'si uchun bittadan). Natijada build paytida/products/1,/products/2, ... — statik HTML generatsiya qilinadi (SSG — 13.4 — fayl sifatida, eng tez). Nega: dinamik yo'l ([id]) qulayligi + statik tezlik (build'da oldindan) — masalan blog post yoki mahsulot sahifalari (ma'lum, o'zgarmaydigan kontent) statik bo'lsa, eng tez ochiladi. Ikki nuqta: (1)generateStaticParams— dinamik[id]yo'llarni build paytida statik qiladi (SSG — 13.4); (2) blog, docs, mahsulot (ma'lum va kam o'zgaradigan) uchun statik ideal (tez, CDN'dan). Bu — 13.4'da rendering strategiyalari bilan chuqur ochiladi; hozircha shuni bilib qo'ying: dinamik yo'l ham statik bo'lishi mumkin (generateStaticParamsorqali).
2.9. Parallel va intercepting routes (ilg'or — qisqa)
ILG'OR ROUTING NAQSHLARI (kam, lekin kuchli — qisqa tanishtirish):
PARALLEL ROUTES (@slot) — bir sahifada BIR NECHA mustaqil bo'lak:
app/dashboard/
├── @team/page.tsx @team slot
├── @analytics/page.tsx @analytics slot
└── layout.tsx ikkalasini oladi: { team, analytics, children }
// dashboard'da team va analytics MUSTAQIL (har biri o'z loading/error) — murakkab dashboard
INTERCEPTING ROUTES (.) — yo'lni "ushlab", boshqacha ko'rsatish:
// masalan: rasm galereyasida rasmga bossangiz — MODAL'da ochiladi (URL o'zgaradi,
// lekin to'liq sahifa emas — modal); to'g'ridan URL'da esa — to'liq sahifa
app/feed/(..)photo/[id]/page.tsx /photo/5 ni feed'da MODAL qilib ushlaydi
┌────────────────────────────────────────────────────────────┐
│ Parallel (@slot): bir sahifada ko'p mustaqil bo'lak │
│ Intercepting (.): yo'lni ushlab modal (Instagram rasm kabi) │
└────────────────────────────────────────────────────────────┘
Parallel/intercepting — ilg'or (murakkab dashboard, modal-routing); kam, lekin kuchli
Boshlang'ich loyihada kam kerak; lekin Instagram-uslubdagi modal — interceptingParallel va intercepting routes — App Router'ning ilg'or routing naqshlari (kam ishlatiladi, lekin kuchli — qisqa tanishtirish). Parallel routes (
@slot) — bir sahifada bir necha mustaqil bo'lakni ko'rsatish:app/dashboard/@team/page.tsxva@analytics/page.tsx—layout.tsxikkalasini alohida props sifatida oladi ({ team, analytics, children }), va ular mustaqil render bo'ladi (har biri o'zloading/error'iga ega) — murakkab dashboard uchun (masalan team statistikasi va analytics bir vaqtda, mustaqil yuklanadi). Intercepting routes ((.),(..)) — yo'lni "ushlab", uni boshqacha ko'rsatish: klassik misol — Instagram-uslubdagi rasm galereyasi: feed'da rasmga bossangiz, rasm modalda ochiladi (URL o'zgaradi/photo/5, lekin to'liq sahifa emas — modal feed ustida), lekin o'sha URL'ni to'g'ridan ochsangiz (yoki yangilasangiz) — to'liq sahifa. Ikki nuqta: (1) parallel (@slot) — bir sahifada ko'p mustaqil bo'lak (murakkab dashboard); intercepting ((.)) — yo'lni ushlab modal qilish (Instagram rasm, "quick view"); (2) bular ilg'or (boshlang'ich loyihada kam kerak), lekin murakkab UX (modal-routing, mustaqil panellar) uchun juda kuchli. Hozircha shuni bilib qo'ying: bunday narsalar mumkin (kerak bo'lganda o'rganasiz); ko'p ilova bularsiz ham ishlaydi. Bu — App Router'ning chuqurligini ko'rsatadi (React Router bunday narsani oson qila olmas edi).
2.10. Template vs layout va routing best practices
TEMPLATE vs LAYOUT (nozik farq):
layout.tsx navigatsiyada SAQLANADI (state qoladi, qayta render yo'q — 2.3)
template.tsx HAR navigatsiyada YANGI nusxa (state reset, qayta render)
template kam (masalan har sahifada kirish animatsiyasi, yoki useEffect har o'tishda)
ROUTING BEST PRACTICES:
page.tsx — faqat sahifa (boshqa komponentlar — alohida fayl/papka)
Komponentlarni _components/ yoki components/da (route emas — 2.1)
Nested layout — umumiy karkas (dashboard sidebar — 2.3)
Route group — turli layout (URL'siz — 2.4)
loading/error har bo'limda (granular — 2.5)
Server Component default; "use client" faqat interaktiv (13.3)
Layout — saqlanadi (afzal); template — har navigatsiyada yangi (kam — maxsus holat)
page.tsx toza (faqat sahifa); komponentlar alohida; layout umumiy karkasTemplate vs layout va best practices — routing'ni to'g'ri tashkil qilish. Template vs layout (nozik farq):
layout.tsx— navigatsiyada saqlanadi (state qoladi, qayta render bo'lmaydi — 2.3 — sidebar misol);template.tsx— har navigatsiyada yangi nusxa (state reset, qayta render bo'ladi).templatekam ishlatiladi — faqat har sahifada yangi boshlanishi kerak bo'lganda (masalan har sahifaga kirish animatsiyasi, yoki har o'tishdauseEffectishlashi kerak). Routing best practices: (1)page.tsx— faqat sahifa (boshqa komponentlarni alohida fayl/papkada); (2) komponentlarni_components/(private — 2.1) yokicomponents/da saqlash (route emas); (3) nested layout — umumiy karkas (dashboard sidebar — 2.3); (4) route group — turli layout (URL'siz — 2.4); (5)loading/errorhar bo'limda (granular — 2.5); (6) Server Component default,"use client"faqat interaktiv 13.3-bob. Ikki nuqta: (1) layout — saqlanadi (afzal — performance, state); template — har navigatsiyada yangi (kam — maxsus holat — animatsiya); (2)page.tsxtoza tut (faqat sahifa), komponentlar alohida, layout umumiy karkas. Bu — tartibli, kengaytiriladigan Next.js routing arxitekturasining asosi.
2.11. Root layout, template va not-found chuqurroq
ROOT LAYOUT (app/layout.tsx) — MAJBURIY, <html> va <body>ni O'ZI beradi:
// app/layout.tsx — butun ilovaning eng tashqi qobig'i (bitta, majburiy)
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="uz"> // <html> va <body> FAQAT root layout'da (boshqa layout'da YO'Q)
<body>{children}</body>
</html>
);
}
┌────────────────────────────────────────────────────────────┐
│ Root layout: MAJBURIY, <html>/<body> — faqat shu yerda │
│ Nested layout: <html>/<body> YO'Q (faqat root'da) │
└────────────────────────────────────────────────────────────┘
NOT-FOUND (404) — ikki usul:
1. app/not-found.tsx butun ilova uchun 404 (yoki segment darajasida — dashboard/not-found.tsx)
2. notFound() funksiya kod ichida 404 chaqirish (next/navigation'dan):
import { notFound } from "next/navigation";
if (!product) notFound(); // ma'lumot topilmasa not-found.tsx ko'rsatiladi
TEMPLATE (template.tsx) — layout kabi, lekin HAR navigatsiyada yangi nusxa:
// app/template.tsx — masalan har sahifaga kirish animatsiyasi
export default function Template({ children }: { children: React.ReactNode }) {
return <div className="fade-in">{children}</div>; // har o'tishda YANGIDAN mount
}
Root layout — bitta, majburiy, <html>/<body> — faqat shu yerda
notFound() — kod ichida 404 (topilmasa); not-found.tsx — 404 UIRoot layout, template va not-found (chuqurroq) — 2.3 va 2.5'ni to'ldiradi. Root layout (
app/layout.tsx) — App Router'da majburiy (har ilovada bo'lishi shart), va u<html>va<body>teglarini o'zi beradi (<html lang="uz"><body>{children}</body></html>). Muhim:<html>/<body>faqat root layout'da bo'ladi — nested layout'lar (dashboard, marketing) ularni takrorlamaydi (faqat o'z<div>ini beradi). not-found (404) — ikki usul: (1)not-found.tsxfayl — butun ilova yoki segment (app/dashboard/not-found.tsx) uchun 404 UI; (2)notFound()funksiya (next/navigation'dan) — kod ichida chaqiriladi (if (!product) notFound()— masalan/products/999topilmasa) va Next.js darrov eng yaqinnot-found.tsxni ko'rsatadi (buredirectga o'xshaydi — render to'xtaydi). template.tsx —layout.tsxka o'xshaydi (childrenoladi), lekin har navigatsiyada yangi nusxa mount qiladi (state reset) — masalan har sahifagafade-inanimatsiyasi yoki har o'tishda ishlashi kerak bo'lganuseEffectuchun. Ikki nuqta: (1) root layout — bitta, majburiy,<html>/<body>faqat shu yerda; (2)notFound()— kod ichidan 404 chaqirish (topilmagan ma'lumot uchun),not-found.tsx— o'sha 404'ning ko'rinishi.
2.12. Route Handlers (route.ts), default.tsx va metadata konvensiyalari
ROUTE HANDLER (route.ts) — sahifa EMAS, API endpoint (06-bob API, 13.7 chuqur):
// app/api/products/route.ts GET/POST /api/products (JSON, HTML emas)
export async function GET() {
const products = await db.products.findMany();
return Response.json(products); // page.tsx UI qaytaradi; route.ts Response
}
page.tsx va route.ts — BIR papkada birga BO'LMAYDI (biri UI, biri endpoint — to'qnashadi)
DEFAULT.tsx — parallel route slot uchun "zaxira" UI (2.9 bilan bog'liq):
// app/dashboard/@analytics/default.tsx slot mos kelmasa shu ko'rsatiladi
// (to'g'ridan URL ochilganda slot holati noma'lum default.tsx zaxira)
METADATA — SEO uchun (08/13.8-bobda chuqur — bu yerda faqat konvensiya):
1. Fayl konvensiyasi: app/favicon.ico, app/icon.png, app/opengraph-image.png (avtomatik)
2. Export konvensiyasi: page.tsx/layout.tsx'da metadata export:
export const metadata = { title: "Mahsulotlar", description: "..." };
export async function generateMetadata({ params }) { ... } // dinamik ([id] uchun)
route.ts — API endpoint (Response), page.tsx — UI (JSX); bir papkada birga emas
metadata — export (statik) yoki generateMetadata (dinamik) — 13.8'da chuqurRoute Handlers, default.tsx va metadata —
app/papkasidagi qolgan maxsus fayllar.route.ts(Route Handler) — bu sahifa emas, balki API endpoint:app/api/products/route.tsGET/POST /api/products(JSON qaytaradi, HTML emas). Ichida HTTP metodlari eksport qilinadi (export async function GET() { return Response.json(...) }). Muhim qoida:page.tsxvaroute.tsbir papkada birga bo'lmaydi — chunki biri UI (GETHTML), boshqasi endpoint (GETJSON) — to'qnashadi. Route Handler'lar 06-bob (API asoslari) va 13.7 (Next.js API)da chuqur ochiladi.default.tsx— parallel route 2.9-bob slot'lari uchun zaxira UI: to'g'ridan URL ochilganda (masalan/dashboardni yangilaganda) slot holati noma'lum bo'lishi mumkin —@analytics/default.tsxo'sha holda ko'rsatiladigan zaxira (fallback). Metadata — SEO uchun (08 va 13.8'da chuqur), bu yerda faqat routing konvensiyasi sifatida: (1) fayl konvensiyasi —app/favicon.ico,app/icon.png,app/opengraph-image.png(Next.js ularni avtomatik<head>ga qo'shadi); (2) export konvensiyasi —page.tsx/layout.tsxdaexport const metadata = { title, description }(statik) yokiexport async function generateMetadata({ params })(dinamik —[id]sahifasi uchun, masalan mahsulot nomi title'ga). Ikki nuqta: (1)route.ts— API endpoint (Response qaytaradi),page.tsx— UI (JSX) — bir papkada birga emas; (2) metadatapage.tsx/layout.tsxda export orqali (13.8'da chuqur).
2.13. Route segment config va streaming UI
ROUTE SEGMENT CONFIG — page/layout/route'dan MAXSUS export bilan xatti-harakatni sozlash
(13.4 rendering bilan chambarchas — bu yerda routing nuqtai-nazaridan):
// app/products/[id]/page.tsx
export const dynamic = "force-dynamic"; // har so'rovda server render (SSG emas)
export const revalidate = 60; // ISR — har 60 soniyada qayta generatsiya 13.4-bob
export const dynamicParams = true; // generateStaticParams'da yo'q id server'da render
export const fetchCache = "force-cache"; // fetch kesh xulqi
STREAMING UI (loading.tsx bilan bog'liq — 2.5):
loading.tsx = butun sahifa uchun Suspense fallback
<Suspense> QO'LDA = sahifaning BIR QISMINI stream (sekin bo'lakni alohida yuklash):
<Suspense fallback={<Spinner />}><SlowComponent /></Suspense>
sahifaning tez qismi darrov, sekin bo'lak (SlowComponent) tayyor bo'lganda "oqib" keladi
Segment config — export const dynamic/revalidate/... (sahifa xulqini sozlash — 13.4)
Streaming — loading.tsx (butun) yoki <Suspense> (qisman) — sekin qism alohida oqadiRoute segment config va streaming UI — sahifa xatti-harakatini sozlash (13.4 rendering bilan ko'prik, bu yerda routing nuqtai-nazaridan qisqacha). Route segment config —
page.tsx,layout.tsxyokiroute.tsdan maxsusexport constorqali segmentning xulqini boshqarish:export const dynamic = "force-dynamic"(har so'rovda server render — statik emas),export const revalidate = 60(ISR — har 60 soniyada qayta generatsiya — 13.4),export const dynamicParams = true(generateStaticParams'da bo'lmaganidkelsa server'da render qilinadimi),export const fetchCache(fetch keshi xulqi). Bu eksportlar routing segmentiga biriktiriladi va 13.4'da chuqur ochiladi. Streaming UI —loading.tsx2.5-bob bilan bog'liq:loading.tsx— butun sahifa uchun Suspense fallback; qo'lda<Suspense>esa sahifaning bir qismini stream qiladi (<Suspense fallback={<Spinner />}><SlowComponent /></Suspense>) — sahifaning tez qismi darrov ko'rinadi, sekin bo'lak (masalan sekin API) tayyor bo'lganda "oqib" keladi (progressiv yuklash — foydalanuvchi bo'sh ekranni kutmaydi). Ikki nuqta: (1) segment config —export const dynamic/revalidate/... bilan sahifa xulqini sozlash 13.4-bob; (2) streaming —loading.tsx(butun sahifa) yoki<Suspense>(qisman — sekin bo'lak alohida oqadi).
2.14. App Router va Pages Router routing farqi
APP ROUTER (app/) vs PAGES ROUTER (pages/) — routing jihatidan farq:
┌──────────────────┬───────────────────────┬───────────────────────┐
│ │ PAGES ROUTER (eski) │ APP ROUTER (yangi) │
├──────────────────┼───────────────────────┼───────────────────────┤
│ Papka │ pages/ │ app/ │
│ Sahifa fayli │ pages/about.tsx = /about│ app/about/page.tsx │
│ Dinamik │ pages/[id].tsx │ app/[id]/page.tsx │
│ Layout │ _app.tsx (bitta global)│ layout.tsx (nested) │
│ Loading/Error │ qo'lda │ loading.tsx/error.tsx │
│ Router hook │ next/router (useRouter)│ next/navigation │
│ Data fetching │ getServerSideProps/... │ async Server Component │
│ Default render │ har xil │ Server Component │
└──────────────────┴───────────────────────┴───────────────────────┘
Pages Router (eski) — pages/, next/router, getServerSideProps; App Router — app/, next/navigation
Ikkalasi bir loyihada ishlashi mumkin (migratsiya), lekin yangi loyiha — App RouterApp Router va Pages Router farqi — Next.js'da ikki routing tizimi bor va ularni chalkashtirmaslik muhim. Pages Router (eski,
pages/papka) —pages/about.tsx/about, dinamikpages/[id].tsx, bitta global layout (_app.tsx), navigatsiyanext/router'dan (useRouter), ma'lumot olishgetServerSideProps/getStaticProps. App Router (yangi,app/papka — Next.js 13+) —app/about/page.tsx/about, nested layout (layout.tsx),loading.tsx/error.tsxavtomatik, navigatsiyanext/navigation'dan, ma'lumot olish to'g'ridan async Server Component'da, default — Server Component. Ikki nuqta: (1) eng keng chalkashlik —next/router(Pages) vanext/navigation(App) — App Router'da doimnext/navigation; (2) ikkalasi bir loyihada birga ishlashi mumkin (bosqichma-bosqich migratsiya uchun), lekin yangi loyiha uchun App Router tavsiya etiladi (bu bob va butun 13-qism App Router'ga bag'ishlangan). Bu farqni bilish eski qo'llanmalar (Pages Router) bilan chalkashmaslik uchun zarur.
3. Sintaksis — tez ma'lumotnoma
SAHIFA 2.1-bob: app/products/page.tsx /products (papka=yo'l, page.tsx=sahifa)
DINAMIK 2.2-bob: [id] /products/42 | [...slug] /docs/a/b | [[...slug]] optional
PARAMS 2.2-bob: async function Page({ params }) { const { id } = await params }
LAYOUT 2.3-bob: app/dashboard/layout.tsx — { children } (ichma-ich o'raydi)
ROUTE GROUP 2.4-bob: app/(marketing)/about/page.tsx /about (qavs URL'da yo'q)
MAXSUS 2.5-bob: page | layout | loading | error("use client") | not-found
LINK 2.6-bob: <Link href="/x"> | router.push() (useRouter — "use client") | redirect() (server)
PATH 2.7-bob: usePathname() | useSearchParams() (Client) | params/searchParams props (Server)
STATIC 2.8-bob: generateStaticParams() — [id] yo'llar uchun statik (SSG — 13.4)
ILG'OR 2.9-bob: @slot (parallel) | (.) (intercepting — modal) | default.tsx (slot zaxira)
ROOT 2.11-bob: app/layout.tsx — <html>/<body> (majburiy) | notFound() | template.tsx
ROUTE.TS 2.12-bob: app/api/.../route.ts — GET/POST (API, Response — 06/13.7); page.tsx bilan birga emas
META 2.12-bob: export const metadata = {...} | generateMetadata() (dinamik — 13.8)
CONFIG 2.13-bob: export const dynamic/revalidate/dynamicParams (segment config — 13.4)
STREAM 2.13-bob: loading.tsx (butun) | <Suspense> (qisman — sekin bo'lak oqadi)
FARQ 2.14-bob: Pages Router (pages/, next/router) vs App Router (app/, next/navigation)4. Batafsil kod namunalari
Har misol: Maqsad + izohli kod + "Bu kod nima qiladi".
Misol 1 — Dinamik mahsulot sahifasi ([id] + params — 2.2)
Maqsad: Bitta fayl bilan cheksiz mahsulot sahifasini yaratish — [id] dinamik segmenti va sahifa params'ni qanday olishini ko'rsatish. Bu e-commerce, blog, profil kabi har dinamik kontentning asosi.
// app/products/[id]/page.tsx — [id] dinamik (har id uchun shu sahifa)
export default async function ProductPage({
params, // Next.js sahifaga params'ni props sifatida beradi
}: {
params: Promise<{ id: string }>; // Next.js 15: params Promise (async)
}) {
const { id } = await params; // URL'dan id'ni ol (/products/42 id = "42")
// id bilan server'da to'g'ridan ma'lumot ol (Server Component — 13.1: Misol 5):
const res = await fetch(`https://api.example.com/products/${id}`);
const product = await res.json();
return (
<main>
<h1>{product.name}</h1> {/* o'sha id'dagi mahsulot */}
<p>{product.price} so'm</p>
</main>
);
}Bu kod nima qiladi: app/products/[id]/page.tsx faylida [id] — dinamik segment: u /products/42, /products/100, /products/abc — har qanday qiymatga mos keladi (bitta fayl, cheksiz sahifa). Next.js sahifa komponentiga params prop'ini beradi — bu URL'dagi dinamik qiymatlarni o'z ichiga oladi. Next.js 15'da params — Promise (shuning uchun await params) — bu so'rov ma'lumotlarining async tabiati uchun (13.1: 2.10). const { id } = await params bilan URL'dan idni ajratib olamiz (/products/42 id = "42"). Keyin shu id bilan server'da to'g'ridan ma'lumot olamiz (await fetch(.../products/${id}) — Server Component, useEffect/useState yo'q — 13.1: Misol 5), va o'sha mahsulotni ko'rsatamiz. Demak: [id] — dinamik yo'l, params — qiymat, va server'da ma'lumot = bitta fayl bilan cheksiz, tez, SEO'li mahsulot sahifalari. Bu — React Router'ning useParams (11.9: 2.6) bilan o'xshash, lekin server'da (props orqali, hook emas).
Misol 2 — Nested layout (dashboard sidebar — 2.3)
Maqsad: Faqat dashboard bo'limida ko'rinadigan sidebar yaratish (boshqa sahifalarda emas) — nested layout'ning ichma-ich o'rash xususiyatini ko'rsatish. Bu murakkab, ko'p-bo'limli ilova strukturasining asosidir.
// app/dashboard/layout.tsx — FAQAT /dashboard/* sahifalari uchun layout
export default function DashboardLayout({
children, // /dashboard ostidagi sahifalar bu yerga keladi
}: {
children: React.ReactNode;
}) {
return (
<div className="dashboard">
{/* Sidebar — /dashboard ostidagi BARCHA sahifada ko'rinadi */}
<aside className="sidebar">
<nav>
<a href="/dashboard">Bosh</a>
<a href="/dashboard/settings">Sozlamalar</a>
<a href="/dashboard/analytics">Analitika</a>
</nav>
</aside>
{/* Asosiy kontent — URL'ga qarab o'zgaradi (settings yoki analytics) */}
<main className="content">{children}</main>
</div>
);
}Bu kod nima qiladi: app/dashboard/layout.tsx — bu nested layout (faqat dashboard/ papka ichidagi sahifalar uchun). U children prop'ini oladi — bu yerga /dashboard ostidagi har qanday sahifa (page.tsx, settings/page.tsx, analytics/page.tsx) avtomatik joylashtiriladi (React Router'ning Outlet'iga o'xshaydi — 11.9: 2.7, lekin Next.js fayl strukturasi orqali). Natijada: sidebar /dashboard ostidagi barcha sahifada ko'rinadi (bir marta yoziladi — layout'da), faqat {children} ichi URL'ga qarab o'zgaradi (/dashboard/settings SettingsPage, /dashboard/analytics AnalyticsPage). Eng muhim — bu layout faqat dashboard uchun (/about, /products sahifalarida yo'q — chunki ular dashboard/ papkasida emas). Va layout navigatsiyada saqlanadi (settings'dan analytics'ga o'tganda sidebar qayta render bo'lmaydi — faqat kontent — performance va state saqlash). Bu — root layout (umumiy navbar — har sahifa) + dashboard layout (sidebar — faqat dashboard) — ichma-ich layoutlarning kuchi.
Misol 3 — Route group (turli layout — 2.4)
Maqsad: Auth sahifalari (login/register)ga boshqa layout (markazlashgan, sidebar'siz) berish, lekin URL'ni /auth/login emas, /login qilish — route group'ning URL'ni o'zgartirmasdan guruhlash xususiyatini ko'rsatish.
// app/(auth)/layout.tsx — (auth) guruhi uchun layout (URL'da "auth" YO'Q)
export default function AuthLayout({ children }: { children: React.ReactNode }) {
return (
<div className="auth-layout"> {/* markazlashgan, sidebar'siz (login/register uchun) */}
<div className="auth-card">{children}</div>
</div>
);
}
// app/(auth)/login/page.tsx URL: /login (NOT /auth/login — qavs () URL'da yo'q!)
export default function LoginPage() {
return <h1>Kirish</h1>;
}
// app/(auth)/register/page.tsx URL: /register (NOT /auth/register)
export default function RegisterPage() {
return <h1>Ro'yxatdan o'tish</h1>;
}Bu kod nima qiladi: (auth) — route group (qavs () bilan). Eng muhim: qavs ichidagi papka nomi URL'da ko'rinmaydi — app/(auth)/login/page.tsxning URL'i /login (NOT /auth/login). Nega bu foydali: (auth)/layout.tsx faqat login va register sahifalariga maxsus layout beradi (markazlashgan karta, sidebar va navbar yo'q — login sahifasiga mos), lekin URL'lar toza qoladi (/login, /register — /auth/ prefiksi yo'q). Demak route group ikki narsani ajratadi: fayl tashkiloti (login/register birga, o'z layout'i bilan) va URL (toza, guruh nomi yo'q). Boshqa sahifalar (/dashboard, /products) o'z layout'iga ega (root + dashboard), auth sahifalari esa alohida ((auth) layout). Bu — bir ilovada turli layout'lar (marketing, shop, auth — har biri o'z karkasi) berishning toza usuli, URL strukturasini buzmasdan. Route group'siz, har layout uchun URL'da qo'shimcha segment bo'lardi (/auth/login — keraksiz).
Misol 4 — loading va error (maxsus fayllar — 2.5)
Maqsad: Yuklanish va xato holatlapini avtomatik boshqarish — loading.tsx va error.tsx maxsus fayllarini ko'rsatish. Bu 11.8 (Suspense) va 11.12 (error boundary)ni qo'lda o'ramasdan beradi.
// app/products/loading.tsx — /products yuklanayotganda AVTOMATIK ko'rinadi
export default function Loading() {
// ProductsPage server'da ma'lumot olayot paytda (await fetch) bu ko'rsatiladi:
return <div className="skeleton">Mahsulotlar yuklanmoqda...</div>;
}
// app/products/error.tsx — /products'da xato bo'lsa AVTOMATIK ko'rinadi
"use client"; // error.tsx HAR DOIM Client Component (error boundary client'da — 11.12)
export default function Error({
error, // xato obyekti
reset, // qayta urinish funksiyasi
}: {
error: Error;
reset: () => void;
}) {
return (
<div className="error">
<p>Xatolik: {error.message}</p>
<button onClick={reset}>Qayta urinish</button> {/* reset — qayta render */}
</div>
);
}Bu kod nima qiladi: Ikki maxsus fayl, har biri avtomatik ishlaydi (11.8 va 11.12'ni qo'lda yozmasdan). loading.tsx — /products sahifasi (Server Component) ma'lumot olayot paytda (await fetch — 13.1: Misol 5), Next.js avtomatik shu Loadingni ko'rsatadi (<Suspense fallback>ni o'zi o'raydi — siz qo'lda o'ramaysiz — 11.8). Ma'lumot tayyor bo'lganda — to'liq sahifa. error.tsx — agar /products sahifasida xato yuz bersa (masalan fetch muvaffaqiyatsiz), Next.js avtomatik shu Errorni ko'rsatadi (error boundary'ni o'zi o'raydi — 11.12). error.tsx har doim "use client" (Client Component) bo'lishi shart — chunki error boundary brauzerda ishlaydi va reset funksiyasi interaktiv. error prop — xato obyekti (xabarni ko'rsatish), reset — qayta urinish (komponentni qaytadan render qiladi). Natijada: foydalanuvchi hech qachon oq ekran yoki to'liq qulagan ilova ko'rmaydi — yuklanishda skeleton, xatoda "qayta urinish" tugmasi. Va bu faqat fayl yaratish bilan (qo'lda Suspense/error boundary — 11.8, 11.12 — kerak emas). Bu — fayl konvensiyasining kuchi.
Misol 5 — Dasturiy navigatsiya (useRouter — login oqimi — 2.6)
Maqsad: Login muvaffaqiyatli bo'lgandan keyin foydalanuvchini dashboard'ga kod orqali yo'naltirish — useRouterning dasturiy navigatsiyasini ko'rsatish (foydalanuvchi bosadigan havola emas, hodisa natijasida).
"use client"; // useRouter — hook Client Component
import { useRouter } from "next/navigation"; // App Router (next/router EMAS — 2.6)
import { useState } from "react";
export default function LoginForm() {
const router = useRouter(); // dasturiy navigatsiya uchun
const [error, setError] = useState("");
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
const res = await fetch("/api/login", { method: "POST", /* ... */ });
if (res.ok) {
router.push("/dashboard"); // muvaffaqiyat dashboard'ga (kod orqali)
router.refresh(); // server holatini yangila (auth tekshiruvi)
} else {
setError("Email yoki parol noto'g'ri");
}
}
return (
<form onSubmit={handleSubmit}>
{error && <p className="error">{error}</p>}
<button type="submit">Kirish</button>
</form>
);
}Bu kod nima qiladi: Bu — login formasi, va u dasturiy navigatsiyani ko'rsatadi (<Link> — foydalanuvchi bosadigan havola — emas, balki kod hodisa natijasida yo'naltiradi). "use client" — chunki useRouter hook va forma interaktiv (useState, onSubmit). useRouter() — next/navigation'dan (App Router — diqqat: next/router Pages Router'niki, eski — 2.6). Forma yuborilganda: server'ga login so'rovi yuboriladi; agar muvaffaqiyatli (res.ok) — router.push("/dashboard") foydalanuvchini dashboard'ga kod bilan yo'naltiradi (foydalanuvchi bosmasdan — login muvaffaqiyatli bo'lgani uchun), va router.refresh() server holatini yangilaydi (auth o'zgardi — server'dagi protected sahifalar endi ruxsat beradi); agar muvaffaqiyatsiz — xato ko'rsatiladi. Demak useRouter — interaktiv oqimlar (login, forma submit, shartli yo'naltirish) uchun (11.9: 2.9 React Router'ning useNavigateiga o'xshaydi). router.push (o'tish), router.replace (orqaga qaytmasin), router.back (orqaga), router.refresh (server'dan yangila) — har biri o'z holati uchun.
Misol 6 — Active link (usePathname — 2.7)
Maqsad: Navbar'da joriy sahifani ajratib ko'rsatish (active link) — usePathname bilan joriy yo'lni olib, mos havolani belgilash. Bu har navbar'ning standart ehtiyoji.
"use client"; // usePathname — hook Client Component
import Link from "next/link";
import { usePathname } from "next/navigation";
export default function Navbar() {
const pathname = usePathname(); // joriy yo'l ("/products" kabi)
// Yordamchi — havola joriy sahifami (active class uchun):
const linkClass = (href: string) =>
pathname === href ? "nav-link active" : "nav-link";
return (
<nav>
<Link href="/" className={linkClass("/")}>Bosh</Link>
<Link href="/products" className={linkClass("/products")}>Mahsulotlar</Link>
<Link href="/about" className={linkClass("/about")}>Biz haqimizda</Link>
</nav>
);
}Bu kod nima qiladi: Bu — navbar, va u joriy sahifani ajratadi (foydalanuvchi qaerda ekanini ko'rsatadi — yaxshi UX). "use client" — chunki usePathname hook (brauzerda joriy URL'ni biladi). usePathname() — joriy yo'lni qaytaradi (/products sahifasida bo'lsak — "/products"). linkClass yordamchi funksiya — havola hrefini joriy pathname bilan solishtiradi: agar mos kelsa "active" class qo'shadi (CSS'da o'sha havolani ajratadi — masalan ko'k rang, ostida chiziq). Natijada: /products sahifasida bo'lganda, "Mahsulotlar" havolasi active class oladi (vizual ajralib turadi), qolganlari oddiy. Bu — React Router'ning <NavLink>iga (11.9: 2.5) o'xshaydi, lekin Next.js'da usePathname + <Link> bilan qo'lda (yoki shadcn/o'z komponentingda o'rab). Eslatma: bu komponent "use client" (hook ishlatadi), shuning uchun u client'da render bo'ladi — lekin u root layout'dagi server komponent ichida ishlatsa bo'ladi (server ichida client — 13.1: Misol 10). Navbar — interaktiv (active link), shuning uchun client mantiqli.
Misol 7 — Catch-all route ([...slug] — docs — 2.2)
Maqsad: Ko'p qatlamli yo'llarni (docs/wiki — /docs/guide/intro/setup) bitta fayl bilan boshqarish — [...slug] catch-all segmentini ko'rsatish. Bu hujjat (documentation) saytlari uchun ideal.
// app/docs/[...slug]/page.tsx — [...slug] BARCHA ostki yo'lni ushlaydi
export default async function DocsPage({
params,
}: {
params: Promise<{ slug: string[] }>; // slug — MASSIV (segmentlar)
}) {
const { slug } = await params;
// /docs/guide/intro slug = ["guide", "intro"]
// /docs/api/auth/login slug = ["api", "auth", "login"]
const path = slug.join("/"); // massivni yo'lga qayta birlashtir
const doc = await fetch(`https://api.example.com/docs/${path}`).then((r) => r.json());
return (
<article>
<h1>{doc.title}</h1>
<div dangerouslySetInnerHTML={{ __html: doc.content }} /> {/* docs HTML */}
</article>
);
}Bu kod nima qiladi: [...slug] — catch-all segment (uch nuqta ... bilan): u /docs ostidagi barcha yo'lni ushlaydi, qancha chuqur bo'lsa ham. Misol: /docs/guide/intro slug = ["guide", "intro"], /docs/api/auth/login slug = ["api", "auth", "login"] — slug massiv bo'ladi (har segment — element). Oddiy [id] (Misol 1) faqat bitta segment oladi (/docs/guide — OK, lekin /docs/guide/intro — yo'q); [...slug] esa istalgan chuqurlikni (/docs/a/b/c/d). slug.join("/") — massivni qayta yo'lga birlashtiradi (["guide", "intro"] "guide/intro"), keyin shu yo'l bilan hujjatni olamiz. Natijada: bitta fayl ([...slug]/page.tsx) butun hujjat (docs) saytini boshqaradi — har sahifa (/docs/guide, /docs/guide/intro, /docs/api/auth/login) shu fayldan render bo'ladi. Bu docs, wiki, ko'p qatlamli kategoriya (/shop/electronics/phones/iphone) kabi noma'lum chuqurlikdagi yo'llar uchun ideal ([id] qila olmas edi — faqat bitta segment). [[...slug]] (optional) bo'lsa, /docs (segmentsiz) ham ishlardi.
Misol 8 — Server'da redirect (auth guard — 2.6, 13.5 ko'prik)
Maqsad: Himoyalangan sahifani server'da tekshirish — agar foydalanuvchi kirmagan bo'lsa, server'da login'ga yo'naltirish (redirect). Bu Client Component guard'dan 11.15-bob tezroq va xavfsizroq.
// app/dashboard/page.tsx — Server Component (himoyalangan)
import { redirect } from "next/navigation"; // server navigatsiya (2.6)
import { getServerSession } from "@/lib/auth"; // server'da sessiyani tekshir (13.9)
export default async function DashboardPage() {
// Server'da auth tekshir (komponent render BO'LISHIDAN OLDIN):
const session = await getServerSession();
if (!session) {
redirect("/login"); // kirmagan server'da login'ga (render to'xtaydi)
}
// Bu yerga faqat AUTENTIFIKATSIYADAN o'tgan foydalanuvchi yetadi:
return <h1>Dashboard — {session.user.name}</h1>;
}Bu kod nima qiladi: Bu — himoyalangan dashboard sahifasi, va himoya server'da amalga oshiriladi (Client Component guard — 11.15: 2.6 — emas). DashboardPage Server Component (async) — server'da render bo'lishdan oldin auth tekshiriladi: await getServerSession() (server'da sessiya/token tekshir — 13.9). Agar sessiya yo'q (!session — foydalanuvchi kirmagan), redirect("/login") — server'da login'ga yo'naltiradi (next/navigation'dan — server navigatsiya — 2.6). Muhim: redirect chaqirilganda, komponent render to'xtaydi (returndan keyingi kod ishlamaydi) — foydalanuvchi dashboard'ni umuman ko'rmaydi (server uni render qilmaydi ham). Agar sessiya bor — komponent davom etadi va foydalanuvchi ma'lumoti bilan dashboard'ni ko'rsatadi. Nega server guard yaxshiroq (Client guard'dan — 11.15): (1) tezroq — server darrov yo'naltiradi (brauzer JavaScript yuklanishini kutmasdan); (2) xavfsizroq — himoyalangan kontent brauzerga umuman yuborilmaydi (Client guard'da kontent yuboriladi, keyin yashiriladi — texnik jihatdan ko'riladi). Bu — Next.js'ning server-first auth naqshi (13.9'da chuqur — NextAuth bilan).
Misol 9 — Komponentlarni tashkil qilish (route emas — 2.1, 2.10)
Maqsad: Sahifaga tegishli komponentlarni qaerda saqlash kerakligini ko'rsatish — page.tsxni toza tutish va komponentlarni route bo'lishdan saqlash. Bu loyiha tashkilotining muhim qismi.
// app/products/_components/ProductCard.tsx
// _components — "_" bilan (private papka — route'ga AYLANMAYDI — 2.1)
export function ProductCard({ product }: { product: Product }) {
return <div className="card">{product.name}</div>;
}
// app/products/page.tsx — sahifa (toza — faqat sahifa mantig'i)
import { ProductCard } from "./_components/ProductCard"; // local komponent
export default async function ProductsPage() {
const products = await fetch("https://api.example.com/products").then((r) => r.json());
return (
<div className="grid">
{products.map((p: Product) => (
<ProductCard key={p.id} product={p} /> {/* tashkillangan komponent */}
))}
</div>
);
}Bu kod nima qiladi: Bu — loyiha tashkilotining muhim naqshi: sahifaga tegishli, lekin route bo'lmasligi kerak bo'lgan komponentlarni qaerda saqlash. _components — private papka (_ bilan boshlanadi) — Next.js uni route sifatida ko'rmaydi (_ bilan boshlangan papka URL'ga aylanmaydi — 2.1). Demak app/products/_components/ProductCard.tsx — /products/_components/ProductCard URL'i emas (faqat tashkilot — komponent fayli). Bu nega muhim: agar oddiy components/ papka yaratsangiz, u ham route bo'lmaydi (faqat page.tsx route bo'ladi — 2.1), lekin _ prefiksi aniq "bu route emas" deb bildiradi (toza, niyat aniq). page.tsx esa toza qoladi — faqat sahifa mantig'i (ma'lumot olish, layout), komponentlar (ProductCard) alohida faylda. Natijada: sahifaga yaqin komponentlar (_components/da — sahifa bilan birga, lekin route emas), umumiy komponentlar esa app/components/ yoki src/components/da (butun ilova bo'ylab). Bu — page.tsxni toza, o'qish oson tutishning va komponentlarni mantiqiy tashkil qilishning usuli (2.10 best practice).
Misol 10 — generateStaticParams (blog SSG — 2.8)
Maqsad: Blog post'larni build paytida statik (SSG) qilish — generateStaticParams bilan barcha post'lar uchun oldindan HTML generatsiya. Bu eng tez yuklanadigan blog uchun.
// app/blog/[slug]/page.tsx
// Build paytida ishlaydi — qaysi slug'lar uchun statik sahifa generatsiya (SSG — 13.4):
export async function generateStaticParams() {
const posts = await fetch("https://api.example.com/posts").then((r) => r.json());
// Har post uchun { slug } qaytar (build'da /blog/post-1, /blog/post-2... statik):
return posts.map((post: { slug: string }) => ({ slug: post.slug }));
}
// Sahifa (har slug uchun — build'da statik HTML):
export default async function BlogPostPage({ params }: { params: Promise<{ slug: string }> }) {
const { slug } = await params;
const post = await fetch(`https://api.example.com/posts/${slug}`).then((r) => r.json());
return (
<article>
<h1>{post.title}</h1>
<div dangerouslySetInnerHTML={{ __html: post.content }} />
</article>
);
}Bu kod nima qiladi: Bu — blog post sahifasi, va u build paytida statik (SSG — eng tez — 13.4) generatsiya qilinadi. generateStaticParams — maxsus, build paytida ishlaydigan funksiya: u barcha blog post'larni olib (fetch(.../posts)), har biri uchun { slug } qaytaradi. Next.js bu ro'yxatni ko'rib, build paytida har slug uchun statik HTML generatsiya qiladi: /blog/post-1.html, /blog/post-2.html, ... — oldindan tayyor fayllar. Natijada: foydalanuvchi /blog/my-first-postni ochsa, server darrov tayyor HTML faylni beradi (server'da render kutish yo'q, ma'lumot olish yo'q — fayl allaqachon tayyor — eng tez, CDN'dan ham beriladi). Bu SSR'dan (har so'rovda server render) tezroq, chunki ish build paytida bir marta qilingan. Nega blog uchun ideal: blog post'lar kam o'zgaradi (yozilgach — statik), shuning uchun har so'rovda qayta render qilishning ma'nosi yo'q — bir marta build'da generatsiya qilib, statik berish eng samarali. generateStaticParams'siz, bu sahifa SSR (har so'rovda server render) yoki on-demand bo'lardi. Bu — 13.4'da rendering strategiyalari bilan chuqur ochiladi; hozircha bil: dinamik yo'l ([slug]) + generateStaticParams = statik tezlik.
5. To'g'ri va noto'g'ri holatlar
1) Sahifa fayli
app/products/index.tsx (Next.js page.tsx kutadi)
app/products/page.tsx (aniq nom — 2.1)2) Navigatsiya import
import { useRouter } from "next/router" (Pages Router — eski — 2.6)
import { useRouter } from "next/navigation" (App Router)3) params
const { id } = params (Next.js 15 — params Promise — 2.2)
const { id } = await params (async)4) error.tsx
error.tsx Server Component (error boundary client'da — 2.5)
"use client" (majburiy)5) Route group
app/auth/login /auth/login (auth URL'da)
app/(auth)/login /login (qavs URL'siz — 2.4)6) usePathname server'da
Server Component'da usePathname (hook — client kerak)
"use client" (Client Component'da — 2.7) yoki params props (Server)6. Keng tarqalgan xatolar va yechimlari
Xato 1 — Sahifa 404 (mavjud bo'lsa ham)
Sababi: fayl page.tsx emas (masalan Page.tsx, index.tsx), yoki default export yo'q 2.1-bob. Yechimi: aniq page.tsx + export default.
Xato 2 — useRouter undefined / xato
Sababi: next/router (Pages Router) import qilindi 2.6-bob. Yechimi: next/navigation'dan import; "use client".
Xato 3 — params should be awaited
Sababi: Next.js 15 — params Promise, await qilinmagan 2.2-bob. Yechimi: const { id } = await params.
Xato 4 — error.tsx ishlamaydi
Sababi: "use client" yo'q 2.5-bob. Yechimi: error.tsx tepasiga "use client".
Xato 5 — Route group URL'da ko'rinadi
Sababi: qavs () yo'q (oddiy papka). Yechimi: (group) (qavs — URL'da yo'q — 2.4).
Xato 6 — Layout har navigatsiyada reset bo'ladi
Sababi: template.tsx ishlatilgan (layout o'rniga — 2.10). Yechimi: layout.tsx (saqlanadi); template faqat maxsus holat.
Xato 7 — Komponent fayli route bo'lib qoldi
Sababi: komponent page.tsx deb nomlangan yoki noto'g'ri joyda. Yechimi: komponentni _components/da (private — 2.1, Misol 9); faqat sahifa page.tsx.
7. Integratsiya — bu mavzu stack'ning qayerida uchraydi
- React Router 11.9-bob: App Router — uning Next.js, fayl-asosli versiyasi (kuchliroq).
- Server Components 13.3-bob: routing + ma'lumot — integratsiyalangan (Misol 1, 8).
- Rendering 13.4-bob: generateStaticParams — dinamik yo'l SSG (Misol 10).
- Auth 13.9-bob: server redirect (auth guard — Misol 8).
- Loading/error (11.8, 11.12): loading.tsx/error.tsx — avtomatik (Misol 4).
- Layout (11.9: 2.7): nested layouts — Outlet'ning fayl versiyasi (Misol 2).
- Data fetching 13.5-bob: params/searchParams — sahifa ma'lumoti.
- Metadata/SEO 13.8-bob: har sahifa/layout metadata.
8. Eng yaxshi amaliyotlar (best practices)
- page.tsx faqat sahifa (komponentlar
_components/da — 2.1, Misol 9). next/navigation(App Router —next/routeremas — 2.6).await params(Next.js 15 — 2.2).- Nested layouts (umumiy karkas — dashboard sidebar — 2.3).
- Route group turli layoutga (URL'siz — 2.4).
- loading/error har bo'limda (granular — 2.5).
- error.tsx
"use client"(majburiy — 2.5). - generateStaticParams statik dinamik yo'lga (blog/docs — 2.8).
- Server redirect auth guard'ga (Client guard'dan xavfsizroq — Misol 8).
- Layout saqlanadi (template emas) 2.10-bob.
9. Amaliy loyiha: "Ko'p Sahifali Next.js Sayti (Routing)"
App Router routing'ni — dinamik, nested, group — real saytda mustahkamlash.
Maqsad
Blog + dashboard sayti qur: dinamik post sahifalari, nested dashboard layout, route group (auth), maxsus fayllar.
Talablar (requirements)
- Statik sahifalar: bosh, about, blog ro'yxati (Misol — 2.1).
- Dinamik:
/blog/[slug](post — params — Misol 1, 7). - Catch-all:
/docs/[...slug](hujjat — Misol 7). - Nested layout:
/dashboard/*sidebar bilan (Misol 2). - Route group:
(auth)/login,(auth)/register/login,/register(Misol 3). - Maxsus fayllar: loading.tsx + error.tsx (Misol 4).
- Navigatsiya:
<Link>+ active link (usePathname — Misol 6). - Dasturiy: login router.push (Misol 5).
- Server guard: dashboard redirect (kirmagan login — Misol 8).
- generateStaticParams: blog post statik (Misol 10).
Maslahatlar (hint)
- page.tsx — aniq nom (Xato 1).
next/navigation(next/router emas — Xato 2).await params(Next.js 15 — Xato 3).- error.tsx —
"use client"(Xato 4). - Route group — qavs
()(Xato 5). - Komponentlar —
_components/(route emas — Misol 9).
"Tayyor" mezonlari (acceptance criteria)
- Statik + dinamik sahifalar.
-
[slug]va[...slug](params). - Nested dashboard layout (sidebar).
- Route group (auth URL'siz).
- loading/error (avtomatik).
- Active link (usePathname).
- Dasturiy navigatsiya (useRouter).
- Server guard (redirect).
- generateStaticParams (statik blog).
Yechim kodi ataylab berilmagan — bu loyihani o'zingiz yozib ko'ring.
10. Xulosa va keyingi bobga ko'prik
Bu bobda App Router routing'ni chuqur o'rgandik:
- Fayl-routing (papka/page — 2.1); dinamik segmentlar (
[id]/[...slug]— 2.2); nested layouts 2.3-bob; route groups ((group)— 2.4). - Maxsus fayllar (loading/error/not-found — 2.5); navigatsiya (
<Link>/useRouter/redirect— 2.6); usePathname/useSearchParams 2.7-bob. - generateStaticParams (dinamik SSG — 2.8); parallel/intercepting (ilg'or — 2.9); template va best practices 2.10-bob.
Endi siz Next.js ilovasining skeletini — sahifalar, dinamik yo'llar, nested layout, navigatsiya, maxsus fayllar — fayl strukturasi orqali (kod emas) qura olasiz. Bu React Router'dan 11.9-bob ancha sodda va kuchli.
Keyingi bob — 13.3-bob: Server Components vs Client Components. Next.js App Router'ning eng muhim, eng inqilobiy tushunchasini chuqur o'rganamiz: Server Components (server'da render — default — tez, SEO, ma'lumot to'g'ridan, JavaScript brauzerga yuborilmaydi) vs Client Components ("use client" — interaktivlik, hook, hodisa). Qaysi qachon, ular qanday birga ishlaydi (kompozitsiya), ma'lumot va props qanday o'tadi, va eng keng tuzoqlar. Bu — Next.js'da to'g'ri, tez, samarali ilova qurishning kalitidir.
Foydalanilgan rasmiy/ishonchli manbalar
- Next.js rasmiy hujjati (nextjs.org/docs/app) — "Routing Fundamentals", "Defining Routes", "Pages and Layouts", "Dynamic Routes", "Route Groups", "Loading UI and Streaming", "Error Handling", "Not Found"
- nextjs.org — Linking and Navigating (
<Link>, prefetch), Redirecting (redirect,permanentRedirect) - nextjs.org —
next/navigationAPI:useRouter,usePathname,useSearchParams,redirect,notFound,permanentRedirect - nextjs.org —
generateStaticParams, Route Segment Config (dynamic,revalidate,dynamicParams,fetchCache) - nextjs.org — Parallel Routes (
@slot,default.js), Intercepting Routes ((.),(..),(...)), Project Organization (private folders_folder, colocation) - nextjs.org — Route Handlers (
route.ts— GET/POST/...), Metadata Files vagenerateMetadata(SEO) - nextjs.org — File Conventions:
page,layout,template,loading,error,not-found,route,default; Root Layout (majburiy<html>/<body>) - nextjs.org — App Router va Pages Router taqqoslash (Incremental Adoption / migratsiya qo'llanmasi)
- React rasmiy hujjati (react.dev) — nested layouts,
<Suspense>(loading.tsx va streaming asosi), Error Boundaries (error.tsx asosi)
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!