Mundarija (28)
- Bu darsda
- 1. Nega bu kerak?
- 2. Parallel routes: @slot
- 2.1 Slot — layout'ning qo'shimcha "teshigi"
- 2.2 Soft va hard navigatsiya
- 2.3 default.tsx — slotning zaxirasi
- 2.4 Biz topdik: Next 16.4 da default.tsx siz build to'xtaydi
- 2.5 Slot ichida o'z navigatsiyasi: tablar
- 3. Ushlovchi marshrutlar: (.)
- 3.1 "Ushlab qolish" g'oyasi
- 3.2 Kanondagi tuzilma
- 3.3 Biz topdik: ushlovchi marshrutga "asl" sahifa shart
- 4. Modal oynaning o'zi
- 4.1 RasmOynasi — native <dialog>
- 4.2 Kanon oqim tekshiruvi
- 4.3 Natija oynasida: URL'li modal modeli
- 5. Portfolio qadami: rasm modal'da va commit
- 5.1 Fayllar
- 5.2 Build va o'lchov
- 6. Ko'p uchraydigan xatolar
- 7. Mashqlar
- 1-mashq (oson): belgilarni o'qing
- 2-mashq (o'rta): qaysi manzilni ushlaydi?
- 3-mashq (qiyin): galereya — modal ichida keyingi rasm
- 4-mashq: Portfolio qadami
- 8. Real ishda
- Xulosa
- Manbalar
Next.js parallel va intercepting routes: @slot, default.tsx va URL'li modal
Qisqacha: Parallel routes — bitta layout'da bir nechta mustaqil "oyna":
@modalkabi@bilan boshlangan papka slot bo'ladi va layout'gachildrenbilan yonma-yon prop bo'lib keladi. Ushlovchi marshrut (intercepting route) —(.)kabi belgili papka: ilova ichidan biror manzilga o'tilganda o'sha sahifa o'rniga boshqasini (masalan modal) ko'rsatadi, URL esa haqiqiy manzilga o'zgaradi. Ikkalasi birga URL'li modal beradi: bosilsa — sahifa ustida oyna, havolani ulashsa yoki yangilasa — to'liq sahifa. Slot mos sahifa topmagandadefault.tsxishlaydi; Next 16.4 da u bo'lmasa build to'xtaydi.
Bu darsda
@slotpapka yaratasiz va uni layout'dachildrenyonida chizasiz.default.tsxnega kerakligini soft va hard navigatsiya farqi bilan tushuntirasiz.(.),(..),(...)belgilarini o'qiy olasiz va qaysi manzilni ushlashini aytasiz.portfolioda loyiha rasmini URL'li modal oynada ochasiz — native<dialog>bilan.- Next 16.4 ning ikki qat'iy build tekshiruvini haqiqiy xabar bilan ko'rasiz.
Oldin bilishingiz kerak: Route groups, Layout va template, Modal, drawer, popover, Navigatsiya.
1. Nega bu kerak?
Case study sahifasida loyihaning skrinshoti bor. Uni kattalashtirib ko'rish uchun ikki odatiy yo'l bor, ikkalasi ham chala.
Birinchi yo'l — oddiy modal. Modal, drawer, popover darsidagidek: tugma bosiladi, useState bilan oyna ochiladi. Qulay, lekin URL o'zgarmaydi. Rasmni do'stingizga yubormoqchisiz — havola faqat sahifani ochadi, rasm yopiq. Telefonda «Orqaga» bosilsa — oyna yopilmaydi, butun sahifadan chiqib ketasiz.
Ikkinchi yo'l — alohida sahifa. /loyihalar/vazifalar/rasm — o'z URL'i bor, ulashsa bo'ladi. Lekin bosilganda case study yo'qoladi, foydalanuvchi kontekstdan uziladi.
Bizga ikkalasining yaxshi tomoni kerak: ilova ichida bosilganda — modal, case study orqada turadi; URL esa /loyihalar/vazifalar/rasm bo'ladi. Havolani ochgan yoki sahifani yangilagan odam — to'liq sahifani ko'radi. «Orqaga» — oynani yopadi.
Instagram'ni eslang: lentada rasm bosilsa, u lenta ustida ochiladi, manzil satri esa /p/… ga o'zgaradi. Shu havolani yangi tabda ochsangiz — rasm alohida sahifada. Next.js'da bu naqsh ikki xususiyatning birikmasi: parallel routes va ushlovchi marshrutlar.
2. Parallel routes: @slot
2.1 Slot — layout'ning qo'shimcha "teshigi"
Layout va template darsida layout bitta "teshik" olardi — children. Parallel routes bilan teshiklar ko'payadi. Papka nomi @ bilan boshlansa, u slot (uya) bo'ladi va ota layout'ga o'z nomi bilan prop bo'lib keladi.
Klassik misol — boshqaruv paneli (dashboard), ikki mustaqil blok:
app/panel/
├── @analitika/page.tsx
├── @jamoa/page.tsx
├── layout.tsx
└── page.tsxexport default function PanelLayout({
children,
analitika,
jamoa,
}: LayoutProps<"/panel">) {
return (
<>
{children}
<section>{analitika}</section>
<section>{jamoa}</section>
</>
);
}/panel ochilganda Next.js uchta sahifani bir vaqtda chizadi: page.tsx → children, @analitika/page.tsx → analitika, @jamoa/page.tsx → jamoa. LayoutProps<"/panel"> slot nomlarini o'zi biladi — typegen papkalarni o'qiydi.
Uch muhim qoida:
- Slot — URL segmenti emas.
@analitikaURL'ga kirmaydi:/panel/@analitikadegan manzil yo'q. Bu jihatdan u route group ga o'xshaydi. childrenham slot, faqat yashirin:app/panel/page.tsxaslidaapp/panel/@children/page.tsxbilan bir xil.- Har slot mustaqil. Har biriga o'z
loading.tsxvaerror.tsxni qo'yish mumkin: analitika sekin bo'lsa, jamoa bloki uni kutmaydi; analitika yiqilsa, jamoa bloki ishlayveradi.
2.2 Soft va hard navigatsiya
Endi /panel/sozlamalar sahifasini qo'shsak — app/panel/sozlamalar/page.tsx. Bu manzilda @analitika va @jamoa nima ko'rsatadi? Ularda sozlamalar/page.tsx yo'q-ku.
Next.js ikki holatni ajratadi:
| Navigatsiya | Qanday | Mos kelmagan slot |
|---|---|---|
| Soft (yumshoq) | <Link> bilan, ilova ichida |
Oldingi holatini saqlaydi |
| Hard (qattiq) | Manzil satri, yangilash, yangi tab | default.tsx ni chizadi |
Soft navigatsiyada Next.js qisman render qiladi: faqat o'zgargan slot yangilanadi, qolganlari avvalgi sahifasida qoladi — URL'ga mos kelmasa ham. Hard navigatsiyada esa brauzer hamma narsani noldan so'raydi, Next.js "bu slotda oldin nima edi" degan xotiraga ega emas. Shuning uchun unga zaxira kerak.
2.3 default.tsx — slotning zaxirasi
default.tsx — slot uchun mos sahifa topilmaganda chiziladigan fayl. Kanondagi @modal/default.tsx:
// Slot uchun mos sahifa bo'lmasa (to'g'ridan kirish, yangilash)
// — hech narsa ko'rsatilmaydi (N-08).
export default function ModalYoq() {
return null;
}null — "hech narsa chizma". Modal slot uchun aynan shu kerak: modal faqat ilova ichidan ochilganda bor, boshqa paytda — yo'q.
2.4 Biz topdik: Next 16.4 da default.tsx siz build to'xtaydi
Next.js hujjatining o'zi bu yerda ikki xil gapiradi (16.4.0 paketidagi hujjat, 2026-10-21):
| Hujjat sahifasi | Nima deydi |
|---|---|
| Parallel Routes | default.tsx bo'lmasa, hard navigatsiyada 404 chiziladi |
default.js |
nomli slotda default.tsx bo'lmasa — xato, faylni yozish shart |
| 16-versiyaga o'tish qo'llanmasi | hamma slotga default.js shart, bo'lmasa build yiqiladi |
Birinchi sahifa eski xulqni tasvirlaydi, qolgan ikkitasi — Next 16 nikini. Biz holat 08 dan @modal/default.tsx ni olib tashlab sinadik — build umuman o'tmadi (asosiy qatorlar):
⚠ Strict route matching is enabled by default. This validation indicates a bug in your app's route structure, but you can temporarily restore loose route matching by setting `deprecated.looseRouteMatching` to `true` in your Next.js config.
Error: Parallel route slots cannot render the same URLs
The following layouts have parallel route slots that cannot render the same URLs:
app/(sayt)/loyihalar/layout.tsx
- /loyihalar is missing a matching page or default.tsx in @modal
- /loyihalar/[slug] is missing a matching page or default.tsx in @modal
- /loyihalar/[slug]/rasm is missing a matching page or default.tsx in @modal
Every URL matched by one slot must have a matching page or default.tsx in every sibling slot.Tarjimasi: "Qat'iy marshrut moslashi sukut bo'yicha yoqilgan. … Parallel slotlar bir xil URL'larni chiza olmaydi: /loyihalar uchun @modal da mos sahifa yoki default.tsx yo'q" — va shunday uchta manzil. Oxirgi qator qoidani aytadi: "bitta slot mos keladigan har URL uchun qo'shni har slotda mos sahifa yoki default.tsx bo'lishi shart".
Kuzatganimiz o'tish qo'llanmasiga mos: Next 16 xatoni ish vaqtidagi 404 dan build vaqtiga ko'chirgan. Hujjat bilan amaliyot farq qilsa, ishonadiganimiz — haqiqiy build natijasi. Yaxshi tomoni — xato foydalanuvchiga yetmaydi. Ogohlantirishdagi deprecated.looseRouteMatching — eski (bo'sh) xulqni vaqtincha qaytarish yo'li; nomidagi deprecated "bu yo'l yopilmoqda" degani. Xatoda yana ikki qator bor edi (birinchi xatoning oqibati) — ularni keyingi bo'limda alohida ko'ramiz.
2.5 Slot ichida o'z navigatsiyasi: tablar
Slot ichiga ham layout.tsx va bir nechta sahifa qo'yish mumkin. Masalan @jamoa/page.tsx va @jamoa/arxiv/page.tsx, ustida @jamoa/layout.tsx da ikki havola — «Faol» va «Arxiv». Foydalanuvchi /panel/arxiv ga o'tganda faqat jamoa bloki almashadi, analitika esa joyida qoladi (soft navigatsiya qoidasi). Hujjat buni tablar uchun tavsiya qiladi: har tab — haqiqiy URL, ulashsa bo'ladi.
Bu kuchli, lekin chalkash ham. Har yangi URL uchun har slotda mos sahifa yoki default.tsx kerak — aks holda yuqoridagi «Next 16.4 da default.tsx siz build to'xtaydi» bo'limidagi xato. Slotlar soni ko'paygani sari fayllar soni tez o'sadi. Shuning uchun kichik loyihada parallel routes'ni faqat haqiqiy ehtiyojda (modal, mustaqil panel) ishlatish ma'qul — portfolio da ham bitta slot, faqat modal uchun.
Tekshirib ko'ring:
/panel/sozlamalarga<Link>bilan o'tildi.@analitikadasozlamalaryo'q. Ekranda nima bo'ladi? Endi sahifani yangilang-chi?
Javob
<Link> bilan (soft) — @analitika oldingi holatini (/panel dagi analitikani) ko'rsatishda davom etadi. Yangilanganda (hard) — @analitika/default.tsx chiziladi. U bo'lmasa, Next 16.4 build'ning o'zi o'tmagan bo'lardi.
3. Ushlovchi marshrutlar: (.)
3.1 "Ushlab qolish" g'oyasi
Ushlovchi marshrut (intercepting route) — papka nomining boshidagi maxsus belgi: "ilova ichidan shu manzilga o'tilganda, haqiqiy sahifa o'rniga meni ko'rsat". Belgilar fayl tizimidagi ./ va ../ ga o'xshaydi:
| Belgi | Qaysi manzilni ushlaydi |
|---|---|
(.)rasm |
Shu darajadagi rasm segmentini |
(..)rasm |
Bir daraja yuqoridagi |
(..)(..)rasm |
Ikki daraja yuqoridagi |
(...)rasm |
app ildizidan boshlab |
Muhim: darajalar URL segmentlari bo'yicha sanaladi, fayl tizimi bo'yicha emas. @modal slot va (sayt) guruh segment emas — ular sanalmaydi.
3.2 Kanondagi tuzilma
app/(sayt)/loyihalar/
├── @modal/
│ ├── (.)[slug]/rasm/page.tsx ← modal (ushlaydi)
│ └── default.tsx ← null
├── [slug]/
│ ├── rasm/page.tsx ← to'liq sahifa
│ └── page.tsx ← case study
├── layout.tsx ← {children}{modal}
└── page.tsx@modal/(.)[slug]/rasm ni o'qiymiz. @modal — slot, sanalmaydi. Demak (.) "loyihalar darajasida" degani: u /loyihalar/[slug]/rasm ni ushlaydi. Fayl tizimida u ikki papka chuqurroq turgan bo'lsa ham.
loyihalar/layout.tsx — ikki slotni yonma-yon qo'yadi:
// Parallel route: `modal` slot (@modal papkasi) children bilan
// yonma-yon chiziladi (N-08).
export default function LoyihalarLayout({
children,
modal,
}: LayoutProps<"/loyihalar">) {
return (
<>
{children}
{modal}
</>
);
}Endi ikki ssenariy:
flowchart TB
A["/loyihalar/vazifalar da<br/>rasm bosildi (soft)"] --> B["children: case study qoladi<br/>modal: (.)[slug]/rasm"]
C["/loyihalar/vazifalar/rasm<br/>to'g'ridan yoki yangilash (hard)"] --> D["children: [slug]/rasm — to'liq sahifa<br/>modal: default.tsx → null"]Soft navigatsiyada children slot o'zgarmaydi (case study joyida — oldingi bo'limdagi qoida), modal slot esa ushlovchi sahifani oladi. Hard navigatsiyada ushlash yo'q: children haqiqiy [slug]/rasm/page.tsx ni, modal esa default.tsx ni chizadi.
3.3 Biz topdik: ushlovchi marshrutga "asl" sahifa shart
To'liq sahifa ([slug]/rasm/page.tsx) ni olib tashlab, faqat modalni qoldirsak-chi? Build:
Error: Interception routes must have a canonical route
The following interception routes do not have a canonical route:
- /loyihalar/(.)[slug]/rasm (expected /loyihalar/[slug]/rasm)
Every interception route must have a matching non-interception route so the URL can be loaded directly or refreshed.Tarjimasi: "Ushlovchi marshrutning asl (canonical) marshruti bo'lishi shart. … Har ushlovchi marshrut uchun oddiy marshrut kerak — URL'ni to'g'ridan ochish yoki yangilash mumkin bo'lsin". Bu ham 16.4 ning qat'iy tekshiruvi. Mantiqi oddiy: modal havolasini kimdir ulashsa, uni ochadigan sahifa bo'lishi kerak. Avvalgi bo'limdagi default.tsx siz build'da ham shu xato chiqqan edi — slot xatosi sabab asl sahifa "topilmay" qolgandi.
Tekshirib ko'ring: fayl
app/(sayt)/blog/@modal/(..)loyihalar/[slug]/page.tsx. U qaysi manzilni ushlaydi?
Javob
/loyihalar/[slug]. (sayt) va @modal sanalmaydi; blog — bitta segment. (..) undan bir daraja yuqoriga (ildizga) chiqadi va loyihalar/[slug] ni ushlaydi. Ya'ni blogdan loyiha havolasi bosilsa — loyiha modal'da ochiladi.
4. Modal oynaning o'zi
4.1 RasmOynasi — native <dialog>
Ushlovchi sahifa rasmni RasmOynasi ga o'raydi. U — client komponent:
"use client";
import { useRouter } from "next/navigation";
import { useEffect, useId, useRef } from "react";
// Native <dialog>: Esc, fokus tuzog'i, fokus qaytishi —
// brauzerniki (20-qism qarori). Yopish = tarixda orqaga
// (URL ham qaytadi).
export function RasmOynasi({
sarlavha,
children,
}: {
sarlavha: string;
children: React.ReactNode;
}) {
const router = useRouter();
const oyna = useRef<HTMLDialogElement>(null);
const sarlavhaId = useId();
useEffect(() => {
const d = oyna.current;
if (d && !d.open) d.showModal();
}, []);
return (
<dialog
ref={oyna}
className="rasm-oynasi"
aria-labelledby={sarlavhaId}
onClose={() => router.back()}
>
<h2 id={sarlavhaId}>{sarlavha}</h2>
{children}
<form method="dialog">
<button type="submit">Yopish</button>
</form>
</dialog>
);
}Kanon izohi telefonga sig'ishi uchun uch qatorga bo'lindi. Asosiy qarorlar:
- Native
<dialog>+showModal()— Esc bilan yopish, fokusni oyna ichida ushlash va yopilganda qaytarish brauzerning o'zida. 20-qismda kanon shu yo'lni tanlagan edi (Radix Dialog kanon CSP'si bilan to'qnashardi).showModal()effektda: element DOM'da bo'lgandan keyingina chaqirish mumkin. <form method="dialog">— JS'siz yopish tugmasi: bunday forma yuborilganda brauzer dialogni yopadi.onClose={() => router.back()}— oyna qanday yopilmasin (Esc, «Yopish»), URL ham orqaga qaytadi. Modal URL'ning qismi — yopish ham URL orqali.
4.2 Kanon oqim tekshiruvi
Kanon modal oqimini headless Chrome'da tekshirdi (xom natija):
modal: /loyihalar/vazifalar/rasm | dialog nomi: Vazifalar ilovasi — skrinshot | h1: Vazifalar ilovasi
fokus dialog ichidami: true
Esc dan keyin: /loyihalar/vazifalar | dialog soni: 0
Yopish dan keyin: /loyihalar/vazifalar
to'g'ridan kirish h1: Vazifalar ilovasi — skrinshot | dialog soni: 0
yangilash h1: Vazifalar ilovasi — skrinshotQatorma-qator:
| Qadam | URL | Ekranda |
|---|---|---|
| Rasm bosildi | /loyihalar/vazifalar/rasm |
Dialog ochiq, orqada case study (h1 o'zgarmagan) |
| Esc yoki «Yopish» | /loyihalar/vazifalar |
Dialog yo'q |
| To'g'ridan kirish / yangilash | /loyihalar/vazifalar/rasm |
To'liq sahifa, h1 "… — skrinshot", dialog yo'q |
Bir manzil — ikki xil ko'rinish, va ikkalasi ham to'g'ri.
4.3 Natija oynasida: URL'li modal modeli
Natija oynasida fayl-routing yo'q, lekin xulqni o'quv modeli bilan qayta qurish mumkin. Ushlashni oddiy bayroq bilan taqlid qilamiz: <Link> ning onNavigate i "ilova ichidan o'tdik" deb belgilaydi. Bu Next.js'ning haqiqiy mexanizmi emas — faqat g'oyani ko'rish uchun.
import Link from "next/link";
import { ih, usePathname, useRouter } from "next/navigation";
ih.boshla("/loyihalar/vazifalar");
function CaseStudy() {
return (
<>
<h1>Vazifalar ilovasi</h1>
<Link href="/loyihalar/vazifalar/rasm" onNavigate={onSoft}>
Rasmni kattalashtirish
</Link>
</>
);
}
let soft = false;
function onSoft() {
soft = true; // Next.js: ilova ichidan o'tish — ushlash ishlaydi
}
function Modal() {
const router = useRouter();
return (
<div role="dialog" aria-label="skrinshot">
<p>[rasm] skrinshot</p>
<button onClick={() => router.back()}>Yopish</button>
</div>
);
}
export default function App() {
const path = usePathname();
const isPhoto = path.endsWith("/rasm");
console.log(path, isPhoto ? (soft ? "modal" : "to'liq") : "sahifa");
if (isPhoto && !soft) return <h1>Vazifalar ilovasi — skrinshot</h1>;
return (
<>
<CaseStudy />
{isPhoto && <Modal />}
</>
);
}Konsolda:
/loyihalar/vazifalar sahifa
/loyihalar/vazifalar/rasm modal
/loyihalar/vazifalar sahifaEkranda:
Vazifalar ilovasi
Rasmni kattalashtirishHavola bosilganda URL /rasm ga o'zgardi, lekin case study qoldi va ustida "oyna" chiqdi (ekran("skrinshot") tekshiradi). «Yopish» — router.back(), URL qaytdi, oyna yo'qoldi. Kanon oqimining birinchi uch qatori aynan shunday.
Hard navigatsiyani ko'rish uchun blok boshidagi qatorni ih.boshla("/loyihalar/vazifalar/rasm") ga o'zgartiring: soft hali false, ekranda faqat "Vazifalar ilovasi — skrinshot" — to'liq sahifa.
5. Portfolio qadami: rasm modal'da va commit
5.1 Fayllar
Route groups darsidagi o'zgarishlarga qo'shiladi:
| Fayl | Nima |
|---|---|
loyihalar/layout.tsx |
{children}{modal} |
loyihalar/@modal/default.tsx |
null |
loyihalar/@modal/(.)[slug]/rasm/page.tsx |
Ushlovchi: RasmOynasi + rasm |
loyihalar/[slug]/rasm/page.tsx |
Asl: to'liq sahifa, ← Loyiha havolasi |
loyihalar/_komponentlar/RasmOynasi.tsx |
Client: <dialog>, router.back() |
loyihalar/[slug]/page.tsx |
Case study'da rasm-havola |
public/loyihalar/*.png |
1280×800 namuna rasmlar (o'zingiznikini qo'ying) |
Rasm next/image bilan chiziladi — u next/image darsida ochiladi, hozircha oddiy <img> deb tushuning. Ikkala rasm sahifasida ham generateStaticParams bor: aks holda Fayl-asosli routing darsidagi "uncached or runtime data" build xatosi qaytadi.
5.2 Build va o'lchov
Build jadvalida yangi qatorlar (kanon, holat 08):
├ /loyihalar/(.)[slug]/rasm
│ ├ ◐ /loyihalar/(.)[slug]/rasm
│ ├ ○ /loyihalar/(.)vazifalar/rasm
│ ├ ○ /loyihalar/(.)bahor/rasm
│ └ ○ /loyihalar/(.)landing/rasm
├ /loyihalar/[slug]
│ ├ ◐ /loyihalar/[slug]
│ ├ ○ /loyihalar/vazifalar
│ ├ ○ /loyihalar/bahor
│ └ ○ /loyihalar/landing
└ /loyihalar/[slug]/rasm
├ ◐ /loyihalar/[slug]/rasm
├ ○ /loyihalar/vazifalar/rasm
├ ○ /loyihalar/bahor/rasm
└ ○ /loyihalar/landing/rasmUshlovchi marshrut ham alohida, (.) bilan, oldindan tayyorlangan (○). Bu URL emas — Next.js'ning ichki nomi. Foydalanuvchi uni hech qachon ko'rmaydi.
| Sahifa | JS (gzip) |
|---|---|
/loyihalar/vazifalar |
149.1 KB (+5.7: next/image + modal) |
/loyihalar/vazifalar/rasm |
143.4 KB |
| Boshqa sahifalar | 137.9–143.4 KB |
axe 0 (6 sahifa), hydration 0; lint, tip, format — 0; build 22 s.
git add -A
git commitCommit (kanon): Tuzilma: (sayt) guruhi, _komponentlar; loyiha rasmi modal'da (@modal + (.)[slug]/rasm).
6. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
Parallel route slots cannot render the same URLs |
Slotda default.tsx yo'q |
@slot/default.tsx (return null) |
Interception routes must have a canonical route |
Faqat modal bor, asl sahifa yo'q | [slug]/rasm/page.tsx ni yozing |
| Modal yangilanganda ham ochiq qoladi (eski versiyalar) | default.tsx o'rnida noto'g'ri sahifa |
default.tsx — null |
| Modal ochilmaydi, to'liq sahifa chiqadi | (..) darajasi noto'g'ri sanalgan |
Slot va guruhni sanamang |
| Yopilganda URL o'zgarmaydi | Faqat dialog.close() |
onClose da router.back() |
showModal xatosi |
Element DOM'ga tushmasdan chaqirilgan | useEffect ichida |
Slot prop'i undefined |
Slot papka nomi xato (@Modal / modal) |
@ + layout'dagi prop nomi bir xil |
7. Mashqlar
Mashqlar kurs/mashqlar/23/08-parallel-intercepting/ da.
1-mashq (oson): belgilarni o'qing
app/lenta/(..)rasm/[id]/page.tsx— ushlaydi: ]app/lenta/@modal/(.)post/[id]/page.tsx— ushlaydi: ]app/a/b/(...)kirish/page.tsx— ushlaydi:app/panel/@jamoa/page.tsx— URL:
Yechim
- /rasm/[id] —
lentadan bir daraja yuqori — ildiz. - /lenta/post/[id] —
@modalslot sanalmaydi,(.)—lentadarajasi. - /kirish —
(...)doim ildizdan. - /panel — slot URL'ga kirmaydi; u
/panelsahifasining bir qismi.
2-mashq (o'rta): qaysi manzilni ushlaydi?
Funksiya yozing: interceptedUrl(folder) — ushlovchi papka yo'lini oladi ("app/(sayt)/loyihalar/@modal/(.)[slug]/rasm") va u ushlaydigan URL'ni qaytaradi ("/loyihalar/[slug]/rasm"). Qoidalar: app tashlanadi; (guruh) va @slot sanalmaydi; ushlovchi belgigacha bo'lgan segmentlar — "joriy daraja"; (.) — shu daraja, har (..) — bitta yuqori, (...) — ildiz; belgidan keyingi qism qo'shiladi. Ishora: RegExp bilan ^(\(\.\.\.\)|(\(\.\.\))+|\(\.\)) ni ajrating.
Yechim
const MARK = /^(\(\.\.\.\)|(?:\(\.\.\))+|\(\.\))/;
function interceptedUrl(folder) {
const parts = folder.split("/").slice(1);
const level = [];
for (let i = 0; i < parts.length; i++) {
const part = parts[i];
const m = part.match(MARK);
if (m) {
let base = level;
if (m[1] === "(...)") base = [];
else if (m[1] !== "(.)") {
base = level.slice(0, -(m[1].length / 4));
}
const rest = [part.slice(m[1].length), ...parts.slice(i + 1)];
return "/" + [...base, ...rest].join("/");
}
const isGroup = part.startsWith("(") && part.endsWith(")");
if (!isGroup && !part.startsWith("@")) level.push(part);
}
return null;
}
const folders = [
"app/(sayt)/loyihalar/@modal/(.)[slug]/rasm",
"app/lenta/(..)rasm/[id]",
"app/a/b/(..)(..)kirish",
"app/a/b/(...)kirish",
];
for (const f of folders) console.log(interceptedUrl(f));Konsolda:
/loyihalar/[slug]/rasm
/rasm/[id]
/kirish
/kirish(..) 4 belgidan iborat — m[1].length / 4 nechta daraja yuqoriga chiqishni beradi. (...) alohida tekshiriladi: u ham (.. bilan boshlanadi, shuning uchun regex'da birinchi turibdi. Slot va guruh level ga qo'shilmadi — hujjatdagi "URL segmentlari bo'yicha" qoidasi.
3-mashq (qiyin): galereya — modal ichida keyingi rasm
«URL'li modal modeli» blokini galereyaga aylantiring: PHOTOS = ["1", "2", "3"]. Bosh sahifada uchta havola (/rasm/1 …). Ichkaridan ochilganda — modal: unda «Keyingi» tugmasi router.replace bilan keyingi rasmga o'tadi (tarixga qo'shmasdan — «Yopish» bosilganda bitta back() galereyaga qaytarsin). Oxirgi rasmda «Keyingi» chizilmasin. Modal matni: Rasm 2 / 3.
Yechim
import Link from "next/link";
import { usePathname, useRouter } from "next/navigation";
const PHOTOS = ["1", "2", "3"];
let soft = false;
function Modal({ id }: { id: string }) {
const router = useRouter();
const index = PHOTOS.indexOf(id);
const next = PHOTOS[index + 1];
return (
<div role="dialog" aria-label={`Rasm ${id}`}>
<p>
Rasm {id} / {PHOTOS.length}
</p>
{next && (
<button onClick={() => router.replace(`/rasm/${next}`)}>
Keyingi
</button>
)}{" "}
<button onClick={() => router.back()}>Yopish</button>
</div>
);
}
export default function App() {
const path = usePathname();
const id = path.startsWith("/rasm/") ? path.slice(6) : null;
console.log(path);
if (id && !soft) return <h1>Rasm {id} — to'liq sahifa</h1>;
return (
<>
<h1>Galereya</h1>
{PHOTOS.map((p) => (
<span key={p}>
<Link href={`/rasm/${p}`} onNavigate={() => (soft = true)}>
Rasm {p}
</Link>{" "}
</span>
))}
{id && <Modal id={id} />}
</>
);
}Konsolda:
/
/rasm/1
/rasm/2
/Ekranda:
Galereya
Rasm 1 Rasm 2 Rasm 3Tarix: / → push /rasm/1 → replace /rasm/2. Tarixda ikki qadam qoldi (/, /rasm/2), shuning uchun bitta back() galereyaga qaytardi. push ishlatilsa, «Yopish» avval /rasm/1 ga qaytarardi — foydalanuvchi uchun g'alati: "yopdim, lekin oldingi rasm ochildi". Haqiqiy Next.js'da ham shunday, faqat ushlashni onNavigate emas, (.) papkasi hal qiladi.
4-mashq: Portfolio qadami
O'z portfolio ingizga loyihalar/layout.tsx ({children}{modal}), @modal/default.tsx, ushlovchi @modal/(.)[slug]/rasm/page.tsx, asl [slug]/rasm/page.tsx va RasmOynasi ni qo'shing. Har loyihaga skrinshot (public/loyihalar/<slug>.png). Tekshiring: next start da case study'dagi rasmni bosing — modal, URL /rasm bilan; Esc — URL qaytadi; sahifani /rasm da yangilang — to'liq sahifa. Keyin commit.
Yechim
Namuna — «Portfolio qadami» bo'limidagi fayllar va kanon kodi. Build Parallel route slots cannot render the same URLs bilan to'xtasa — default.tsx yo'q yoki noto'g'ri papkada (u aynan @modal/ ichida bo'lishi kerak). Interception routes must have a canonical route — asl rasm sahifasi yo'q. Modal o'rniga to'liq sahifa ochilsa — (.) darajasini «Kanondagi tuzilma» bo'limidagi daraxt bilan solishtiring. Fokus va Esc'ni klaviatura bilan sinang: Tab oynadan chiqib ketmasligi kerak.
8. Real ishda
- Rasm va post modallari — Instagram, Pinterest, Dribbble naqshi. Do'konlarda mahsulot "tez ko'rish" oynasi: katalogdan bosilsa — modal, havola ulashilsa — to'liq mahsulot sahifasi.
- Kirish oynasi —
(...)kirishbilan istalgan sahifadan login modal'da ochiladi,/kirishga to'g'ridan kirgan odam esa to'liq sahifani ko'radi. - Dashboard'lar — har panel alohida slot: o'z yuklanishi, o'z xatosi. Bitta sekin grafik butun panelni to'xtatmaydi.
- Versiya yangilash — Next 16.4 dagi qat'iy marshrut tekshiruvi eski loyihalarda build'ni to'xtatishi mumkin. Xabarni o'qib, yetishmagan
default.tsxni qo'shish — eng tez yo'l (Versiyalarni yangilash).
Xulosa
@slotpapka layout'gachildrenyonida prop bo'lib keladi; slot URL segmenti emas; har slot o'z loading/error'iga ega.- Soft navigatsiyada mos kelmagan slot eski holatini saqlaydi, hard navigatsiyada
default.tsxchiziladi. - Next 16.4 qat'iy:
default.tsxyo'q slot va asl sahifasiz ushlovchi marshrut — ikkalasi ham build xatosi. (.),(..),(...)— URL segmentlari bo'yicha (slot va guruh sanalmaydi); ilova ichidan o'tishni ushlaydi.- URL'li modal = slot + ushlovchi marshrut + asl sahifa; yopish —
router.back().
Keyingi dars: Server Components — portfolio sahifalari nega brauzerga JS yubormasligini va serverda nima bo'layotganini ochamiz.
Manbalar
- Next.js hujjati — Parallel Routes,
default.js: https://nextjs.org/docs/app/api-reference/file-conventions/parallel-routes (next 16.4.0 paketi ichidagi hujjat, 2026-10-21 da o'qildi) - Next.js hujjati —
default.jsva "How to upgrade to version 16" § Parallel Routesdefault.jsrequirement: https://nextjs.org/docs/app/guides/upgrading/version-16 (16.4.0 paketidagi nusxa, 2026-10-21) - Next.js hujjati — Intercepting Routes: https://nextjs.org/docs/app/api-reference/file-conventions/intercepting-routes
- MDN —
<dialog>vashowModal(): https://developer.mozilla.org/docs/Web/HTML/Element/dialog - Kanon o'lchovlari:
portfoliov2, holat 08 (build jadvali, modal oqimi, JS hajmi).default.tsxsiz va asl sahifasiz build xatolari — biz ishga tushirdik (next 16.4.0).
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!