File-based Routing — papka va fayl orqali route yaratish
Muammodan boshlaylik
React da routing qilish uchun react-router-dom o'rnatib, alohida fayl yaratib, har bir route ni qo'lda yozasiz:
// React — router.tsx
import { createBrowserRouter } from 'react-router-dom'
const router = createBrowserRouter([
{ path: '/', element: <HomePage /> },
{ path: '/about', element: <AboutPage /> },
{ path: '/blog', element: <BlogPage /> },
{ path: '/blog/:slug', element: <BlogPostPage /> },
{ path: '/dashboard', element: <DashboardPage /> },
{ path: '/dashboard/settings', element: <SettingsPage /> },
])
Loyiha o'sgan sari bu fayl uzayib ketadi. Yangi sahifa qo'shsangiz — ikki joyni o'zgartirish kerak: fayl yaratish va router ga qo'shish.
Next.js da router fayli yo'q. Papka yaratdingiz — route tayyor.
Qanday ishlaydi
app/ papkasi ichidagi har bir papka — URL segment. Sahifa bo'lishi uchun papka ichida page.tsx bo'lishi kerak.
app/
├── page.tsx → /
├── about/
│ └── page.tsx → /about
├── blog/
│ └── page.tsx → /blog
└── dashboard/
├── page.tsx → /dashboard
└── settings/
└── page.tsx → /dashboard/settings
Yangi sahifa qo'shish — papka yaratib, ichiga page.tsx qo'yish. Boshqa hech narsa kerak emas.
Dynamic Route — [id]
Ko'p hollarda URL da o'zgaruvchi qism bo'ladi. Masalan, har bir mahsulotning o'z sahifasi bor:
/products/1
/products/2
/products/99
Har bir mahsulot uchun alohida papka yaratib bo'lmaydi. Buning uchun dynamic route ishlatiladi — papka nomini kvadrat qavsga olamiz:
app/
└── products/
├── page.tsx → /products
└── [id]/
└── page.tsx → /products/1, /products/2, ...
[id] — bu o'zgaruvchi. URL dagi qiymat params.id orqali olinadi:
// app/products/[id]/page.tsx
export default async function ProductPage({
params,
}: {
params: { id: string }
}) {
const product = await fetch(
`https://api.example.com/products/${params.id}`
).then(r => r.json())
return (
<div>
<h1>{product.name}</h1>
<p>Narx: {product.price} so'm</p>
</div>
)
}
/products/42 ga kirganda params.id = "42" bo'ladi.
Nested Dynamic Route
Blog da kategoriya va post bo'lishi mumkin:
/blog/javascript/closures
/blog/react/hooks
app/
└── blog/
└── [category]/
└── [slug]/
└── page.tsx
// app/blog/[category]/[slug]/page.tsx
export default async function BlogPost({
params,
}: {
params: { category: string; slug: string }
}) {
// /blog/javascript/closures uchun:
// params.category = "javascript"
// params.slug = "closures"
const post = await fetch(
`https://api.example.com/posts/${params.category}/${params.slug}`
).then(r => r.json())
return <article><h1>{post.title}</h1></article>
}
Catch-all Route — [...slug]
Ba'zan URL ning qancha segment bo'lishini oldindan bilmaysiz. Masalan, hujjatlar sayti:
/docs/getting-started
/docs/api/components/button
/docs/guides/auth/oauth/google
Buning uchun [...slug] ishlatiladi — barcha qolgan segmentlarni tutib oladi:
app/
└── docs/
└── [...slug]/
└── page.tsx
// app/docs/[...slug]/page.tsx
export default function DocsPage({
params,
}: {
params: { slug: string[] }
}) {
// /docs/api/components/button uchun:
// params.slug = ["api", "components", "button"]
return <div>Hujjat: {params.slug.join(' / ')}</div>
}
[[...slug]] — ikki kvadrat qavs — optional catch-all. /docs ga kirganda ham ishlaydi (slug bo'sh massiv bo'ladi).
Route Group — (group)
Ba'zan sahifalarni URL ga ta'sir qilmasdan guruhlash kerak bo'ladi. Masalan, autentifikatsiya sahifalari — login, register, forgot-password — bularning hammasi uchun alohida layout kerak (navbar yo'q, faqat markazlashgan forma).
Papka nomini qavsga olsangiz — u URL ga kirmaydi:
app/
├── (auth)/
│ ├── layout.tsx ← faqat auth sahifalari uchun layout
│ ├── login/
│ │ └── page.tsx → /login (auth emas!)
│ └── register/
│ └── page.tsx → /register
└── (main)/
├── layout.tsx ← asosiy layout (navbar bilan)
├── page.tsx → /
└── about/
└── page.tsx → /about
(auth) va (main) — URL da ko'rinmaydi. Faqat papkalarni tartibga solish uchun.
// app/(auth)/layout.tsx — login/register uchun alohida layout
export default function AuthLayout({ children }: { children: React.ReactNode }) {
return (
<div className="flex items-center justify-center min-h-screen">
{children} {/* navbar yo'q, faqat markazlashgan kontent */}
</div>
)
}
not-found.tsx — sahifa topilmaganda
Foydalanuvchi mavjud bo'lmagan URL ga kirsa — Next.js default 404 sahifasini ko'rsatadi. O'zingizning 404 sahifangizni yaratish uchun not-found.tsx fayli:
app/
└── not-found.tsx ← barcha 404 uchun
// app/not-found.tsx
import Link from 'next/link'
export default function NotFound() {
return (
<div>
<h1>404 — Sahifa topilmadi</h1>
<Link href="/">Bosh sahifaga qaytish</Link>
</div>
)
}
Kod ichida ham chaqirish mumkin — masalan, mahsulot topilmaganda:
import { notFound } from 'next/navigation'
export default async function ProductPage({ params }) {
const product = await fetch(`/api/products/${params.id}`).then(r => r.json())
if (!product) notFound() // 404 sahifasiga yo'naltiradi
return <h1>{product.name}</h1>
}
Tez-tez uchraydigan xatolar
1. params ni await qilmaslik (Next.js 15+)
Next.js 15 dan boshlab params — Promise. await qilmasangiz xato beradi:
// ❌ — Next.js 15 da xato
export default function Page({ params }) {
console.log(params.id) // xato!
}
// ✅
export default async function Page({ params }) {
const { id } = await params
console.log(id)
}
2. Dynamic route papkasini noto'g'ri nomlash
app/products/id/page.tsx ← xato — bu /products/id route
app/products/[id]/page.tsx ← to'g'ri — dynamic route
3. Route group papkasini URL da kutish
app/(auth)/login/page.tsx → /login (to'g'ri)
→ /(auth)/login (xato — bunday URL yo'q)
Xulosa
Next.js da routing — papka tuzilmasi. Router fayli yo'q, konfiguratsiya yo'q.
app/page.tsx → /
app/about/page.tsx → /about
app/products/[id]/page.tsx → /products/:id
app/docs/[...slug]/page.tsx → /docs/* (istalgan chuqurlik)
app/(auth)/login/page.tsx → /login (group URL ga kirmaydi)
notFound() — kod ichida 404 ga yo'naltirish.
Keyingi dars
5-dars: page.tsx, layout.tsx, loading.tsx, error.tsx, not-found.tsx — har birining roli
Bu maxsus fayllarning barchasini bir joyda ko'rib chiqamiz — qachon ishlaydi, qanday o'zaro bog'liq.