Dynamic Route — [id], [...slug], [[...slug]] — farqlari
Muammodan boshlaylik
Siz blog yozdingiz. 1000 ta post bor. Har biri uchun alohida papka yaratib bo'lmaydi:
app/blog/post-1/page.tsx
app/blog/post-2/page.tsx
app/blog/post-3/page.tsx
... (1000 ta)
Bu mantiqsiz. Buning uchun dynamic route — bitta papka, istalgan qiymat uchun ishlaydi.
[id] — bitta segment
Papka nomini kvadrat qavsga olish — o'sha segment dynamic bo'ladi:
app/
└── blog/
└── [slug]/
└── page.tsx → /blog/har-qanday-narsa
// app/blog/[slug]/page.tsx
export default async function BlogPost({ params }) {
const { slug } = await params
// /blog/nextjs-kirish → slug = "nextjs-kirish"
// /blog/react-hooks → slug = "react-hooks"
const post = await db.getPost(slug)
return <article><h1>{post.title}</h1></article>
}
Bir nechta dynamic segment:
app/shop/[category]/[id]/page.tsx
→ /shop/electronics/42
→ params = { category: "electronics", id: "42" }
[...slug] — catch-all
Nechta segment bo'lishini oldindan bilmasangiz — [...slug]:
app/docs/[...slug]/page.tsx
→ /docs/getting-started → slug = ["getting-started"]
→ /docs/api/components/button → slug = ["api", "components", "button"]
→ /docs → 404! (slug bo'sh bo'lmaydi)
// app/docs/[...slug]/page.tsx
export default async function DocsPage({ params }) {
const { slug } = await params
// slug — massiv: ["api", "components", "button"]
const path = slug.join('/') // "api/components/button"
const doc = await getDoc(path)
return <div>{doc.content}</div>
}
/docs ga kirganda — 404. Chunki [...slug] kamida bitta segment talab qiladi.
[[...slug]] — optional catch-all
/docs ham ishlashi kerak bo'lsa — ikki kvadrat qavs:
app/docs/[[...slug]]/page.tsx
→ /docs → slug = undefined
→ /docs/getting-started → slug = ["getting-started"]
→ /docs/api/components/button → slug = ["api", "components", "button"]
// app/docs/[[...slug]]/page.tsx
export default async function DocsPage({ params }) {
const { slug } = await params
// /docs → slug = undefined
// /docs/intro → slug = ["intro"]
if (!slug) {
return <h1>Hujjatlar bosh sahifasi</h1>
}
const doc = await getDoc(slug.join('/'))
return <div>{doc.content}</div>
}
Static va Dynamic birga — ustunlik tartibi
Bir xil darajada static va dynamic route bo'lsa — static ustun:
app/blog/new/page.tsx → /blog/new (static — ustun)
app/blog/[slug]/page.tsx → /blog/new (dynamic — ishlamaydi)
/blog/new ga kirganda — new/page.tsx ishlaydi, [slug] emas.
app/blog/
├── new/
│ └── page.tsx → /blog/new (static, ustun)
└── [slug]/
└── page.tsx → /blog/react-hooks, /blog/nextjs (dynamic)
generateStaticParams — dynamic route uchun SSG
Dynamic route ni build vaqtida statik yaratish uchun:
// app/blog/[slug]/page.tsx
export async function generateStaticParams() {
const posts = await db.getAllPosts()
return posts.map(post => ({ slug: post.slug }))
}
// Catch-all uchun
// app/docs/[...slug]/page.tsx
export async function generateStaticParams() {
const docs = await getAllDocs()
return docs.map(doc => ({
slug: doc.path.split('/') // ["api", "components", "button"]
}))
}
Tez-tez uchraydigan xatolar
1. params ni await qilmaslik (Next.js 15+)
// ❌
export default function Page({ params }) {
const { id } = params // xato! Next.js 15 da params — Promise
}
// ✅
export default async function Page({ params }) {
const { id } = await params
}
2. [...slug] da /docs ga kirish — 404
// ❌ — /docs ga kirsa 404
app/docs/[...slug]/page.tsx
// ✅ — /docs ham ishlaydi
app/docs/[[...slug]]/page.tsx
3. slug massiv ekanini unutish
// ❌ — slug massiv, string emas
const { slug } = await params
const doc = await getDoc(slug) // xato! slug = ["api", "button"]
// ✅
const doc = await getDoc(slug.join('/')) // "api/button"
4. Static va dynamic nomlar to'qnashishi
// ❌ — /blog/new ham [slug] ga tushadi deb o'ylash
app/blog/[slug]/page.tsx → /blog/new (new/page.tsx bo'lmasa)
// ✅ — alohida static route yarating
app/blog/new/page.tsx → /blog/new (static, ustun)
app/blog/[slug]/page.tsx → /blog/react-hooks
Xulosa
[id] → bitta segment: /products/42
[...slug] → bir yoki ko'p segment: /docs/api/button
[[...slug]] → nol yoki ko'p segment: /docs, /docs/api/button
params → Next.js 15 da await kerak
slug → massiv, join('/') bilan string ga aylantirish
Static route → dynamic dan ustun (/blog/new > /blog/[slug])
Keyingi dars
25-dars: Route Group — (group) — URL ga ta'sir qilmasdan guruhlash
Papkalarni URL ga kirmagan holda guruhlash — turli layoutlar, turli middleware lar uchun.