File-based Routing — papka va fayl orqali route yaratish

~15 daq · Next.js · Kirish va Asoslar

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.