Параллельные и перехватывающие маршруты
Продвинутые возможности App Router для сложных UI.
Параллельные маршруты
Позволяют рендерить несколько страниц в одном layout одновременно.
Синтаксис
Папки с @ — слоты:
app/
├── layout.tsx
├── page.tsx
├── @team/
│ └── page.tsx
└── @analytics/
└── page.tsx
Layout
// app/layout.tsx
export default function Layout({
children,
team,
analytics,
}: {
children: React.ReactNode;
team: React.ReactNode;
analytics: React.ReactNode;
}) {
return (
<>
{children}
<div className="grid">
{team}
{analytics}
</div>
</>
);
}
Каждый слот рендерится параллельно и независимо.
default.tsx
Если слот не совпал — используется default.tsx:
// app/@team/default.tsx
export default function Default() {
return null;
}
Иначе — 404.
Перехватывающие маршруты
Позволяют показать маршрут в контексте другого. Классический случай — модалка поверх списка.
Синтаксис
(.)— тот же уровень(..)— уровень выше(..)(..)— два уровня выше(...)— из корня
app/
├── feed/
│ ├── page.tsx
│ └── (..)photo/
│ └── [id]/
│ └── page.tsx ← перехватывает /photo/[id]
└── photo/
└── [id]/
└── page.tsx ← отдельный маршрут
При клике на фото из /feed открывается модалка. При прямом заходе /photo/1 — отдельная страница.
Пример
app/feed/(..)photo/[id]/page.tsx:
export default async function PhotoModal({ params }) {
const { id } = await params;
const photo = await getPhoto(id);
return (
<div className="modal">
<Image src={photo.url} alt={photo.alt} />
</div>
);
}
app/photo/[id]/page.tsx:
export default async function PhotoPage({ params }) {
const { id } = await params;
const photo = await getPhoto(id);
return (
<div className="photo-page">
<Image src={photo.url} alt={photo.alt} />
<Link href="/feed">К ленте</Link>
</div>
);
}
Закрытие модалки
'use client';
import { useRouter } from 'next/navigation';
export function Modal({ children }) {
const router = useRouter();
return (
<div className="backdrop" onClick={() => router.back()}>
<div className="content" onClick={(e) => e.stopPropagation()}>
{children}
</div>
</div>
);
}
router.back() возвращает на предыдущий URL.
Когда использовать
Параллельные:
- Дашборд с несколькими панелями
- Модалки поверх страниц
- Разные layouts для разных секций
Перехватывающие:
- Модалки, сохраняющие URL
- Галереи, где фото открывается поверх ленты
- Логин-модалка вместо отдельной страницы
Сложности
- Требуют внимательного планирования структуры
default.tsxобязателен для слотов- URL и UI могут расходиться
- Не всегда очевидно, какой маршрут перехватится
Итоги
@slot— параллельные маршруты(.),(..),(...)— перехват- Модалки без потери URL
default.tsxдля слотов- Используются для сложных UI