JavaRush /Курсы /Модуль 4: Node.js, Next.js и Angular /Параллельные маршруты в Next.js 15 App Router:

Параллельные маршруты в Next.js 15 App Router: @имя и примеры использования

Модуль 4: Node.js, Next.js и Angular
8 уровень , 6 лекция
Открыта

1. Зачем нужны параллельные маршруты?

Давайте начнём с вопроса: Почему обычной вложенности маршрутов иногда недостаточно?

Представьте себе современное приложение — например, почтовый клиент или личный кабинет пользователя. Часто на экране одновременно отображаются несколько независимых областей, и каждая из них может самостоятельно меняться:

  • Слева — список писем, справа — открытое письмо.
  • Слева — меню, справа — контент, а снизу — всплывающее окно чата.
  • Сверху — шапка, внизу — уведомления, которые не должны сбрасываться при навигации по основному контенту.

В классическом подходе с вложенными маршрутами при переходе на новый маршрут пересоздаётся всё дерево компонентов ниже точки вложенности. Это неудобно, если вы хотите, чтобы некоторые части интерфейса были независимы друг от друга: например, чтобы уведомления или чат оставались на месте, пока пользователь переходит между страницами.

Параллельные маршруты позволяют объявлять такие независимые области прямо в структуре маршрутов, и управлять ими как отдельными потоками UI.

Базовая теория

Параллельные маршруты (Parallel Routes) — это способ объявить в структуре папки app/ несколько "слотов" (outlet-ов), которые могут наполняться разными страницами независимо друг от друга. Каждый слот обозначается специальной папкой с префиксом @, например: @chat, @notifications, @sidebar.

Главная идея:

  • В одном layout-файле (layout.tsx) вы объявляете несколько "слотов" для параллельных маршрутов.
  • Каждый слот может содержать свою страницу (page.tsx) или вложенные маршруты.
  • Эти слоты отображаются одновременно, но управляются отдельно — их содержимое может меняться независимо от других частей страницы.

Аналогия:
Представьте себе многоквартирный дом. Каждый подъезд — это отдельный "слот". Жильцы могут заходить и выходить из своих подъездов, не мешая соседям. А вы как архитектор управляете сразу всеми подъездами из одной схемы.

2. Синтаксис и структура: как объявлять параллельные маршруты?

Основные правила

  • Папка параллельного маршрута всегда начинается с символа @, например: @chat, @sidebar, @modal.
  • В layout-файле вы используете специальные пропсы для отображения этих маршрутов.
  • Каждый параллельный маршрут может иметь свою страницу (page.tsx), layout, template и даже вложенные маршруты.

Пример структуры папки app/ с параллельными маршрутами


app/
  layout.tsx
  page.tsx
  @chat/
    page.tsx
  @notifications/
    page.tsx

В этом примере у нас есть три "слота":

  • Основной контент (page.tsx)
  • Чат (@chat/page.tsx)
  • Уведомления (@notifications/page.tsx)

Как это выглядит в коде?

Файл app/layout.tsx:


export default function RootLayout({ children, chat, notifications }) {
  return (
    <html>
      <body>
        <main>{children}</main>
        <aside>{chat}</aside>
        <div className="notifications">{notifications}</div>
      </body>
    </html>
  );
}

Пояснение:
children — это основной слот (главная страница или вложенные маршруты).
chat, notifications — это параллельные слоты, которые автоматически наполняются содержимым из папок @chat и @notifications.

Важно:
Имена пропсов должны совпадать с именем папки после @.
То есть, если папка называется @chat, то проп в layout-функции должен называться chat.

3. Пример: Чат и уведомления на всех страницах

Давайте разберём практический пример:
Мы хотим, чтобы в нашем приложении всегда был доступен чат (справа) и уведомления (снизу), независимо от того, по какой странице ходит пользователь.

Структура папки


app/
  layout.tsx
  page.tsx
  about/
    page.tsx
  @chat/
    page.tsx
  @notifications/
    page.tsx

Файл app/layout.tsx


export default function RootLayout({ children, chat, notifications }) {
  return (
    <html>
      <body>
        <header>Мой сайт</header>
        <section className="content">{children}</section>
        <aside className="chat">{chat}</aside>
        <footer>
          <div className="notifications">{notifications}</div>
        </footer>
      </body>
    </html>
  );
}

Файл app/page.tsx


export default function HomePage() {
  return <h1>Главная страница</h1>;
}

Файл app/about/page.tsx


export default function AboutPage() {
  return <h1>О нашем проекте</h1>;
}

Файл app/@chat/page.tsx


export default function Chat() {
  return <div>💬 Чат всегда под рукой!</div>;
}

Файл app/@notifications/page.tsx


export default function Notifications() {
  return <div>🔔 Уведомления (их можно обновлять независимо от контента)</div>;
}

В результате:

  • На любой странице (/, /about) справа всегда отображается чат, а внизу — уведомления.
  • При переходе между страницами чат и уведомления не перерисовываются и не сбрасываются.
  • Можно реализовать отдельную навигацию внутри чата или уведомлений, не влияя на основную страницу.

4. Навигация внутри параллельных маршрутов

Параллельные маршруты особенно полезны, когда нужно реализовать независимую навигацию внутри каждого слота.

Пример: Список писем и выбранное письмо (почтовый клиент)


app/
  layout.tsx
  @inbox/
    page.tsx           // Список писем
    [id]/
      page.tsx         // Открытое письмо
  @chat/
    page.tsx           // Чат

В layout-файле:


export default function RootLayout({ inbox, chat }) {
  return (
    <div style={{ display: 'flex' }}>
      <section style={{ flex: 2 }}>{inbox}</section>
      <aside style={{ flex: 1 }}>{chat}</aside>
    </div>
  );
}

В app/@inbox/page.tsx:


import Link from "next/link";

const mails = [
  { id: "1", subject: "Привет!" },
  { id: "2", subject: "Важное письмо" }
];

export default function Inbox() {
  return (
    <ul>
      {mails.map(mail => (
        <li key={mail.id}>
          <Link href={`/inbox/${mail.id}`}>{mail.subject}</Link>
        </li>
      ))}
    </ul>
  );
}

В app/@inbox/[id]/page.tsx:


export default function Mail({ params }) {
  return <div>Открыто письмо с id: {params.id}</div>;
}

Что происходит?

  • Слева отображается список писем или открытое письмо (в зависимости от маршрута).
  • Справа — чат, который всегда на месте.
  • Навигация по письмам не влияет на чат, и наоборот.

5. Полезные нюансы

Совмещение параллельных маршрутов с layout-ами и вложенностью

Параллельные маршруты можно комбинировать с обычными layout-ами и вложенными маршрутами. Например, можно сделать так, чтобы у чата был свой собственный layout:


app/
  layout.tsx
  @chat/
    layout.tsx
    page.tsx
    support/
      page.tsx

В этом случае в app/@chat/layout.tsx вы можете добавить, например, шапку чата или навигацию между чатами поддержки и обычными чатами.

Поведение при навигации: как работают параллельные маршруты

  • При переходе по основным маршрутам (например, /about, /) параллельные маршруты остаются на месте.
  • При переходе внутри самого параллельного маршрута (например, внутри чата) — основной контент не перерисовывается.
  • Это экономит ресурсы и делает интерфейс отзывчивым, особенно если у вас есть тяжёлые компоненты (например, чат или уведомления).

Важный момент:
Если для какого-то маршрута не задан параллельный слот, он будет считаться "пустым" (undefined) — и вы можете показать заглушку или ничего не рендерить.

6. Типичные ошибки при работе с параллельными маршрутами

Ошибка №1: Неправильное имя пропа в layout.
Если папка называется @chat, а в layout вы пишете props.Chat (с большой буквы) или props.messenger — слот не будет заполнен. Имена должны совпадать: @chatchat.

Ошибка №2: Отсутствие слота в layout.
Если вы создали папку @notifications, но забыли добавить проп notifications в параметры функции layout — уведомления не появятся вообще.

Ошибка №3: Попытка вложить параллельный маршрут внутрь другого параллельного маршрута.
Параллельные маршруты работают на одном уровне layout. Вложенность допустима, но требует отдельного layout-файла для каждого уровня.

Ошибка №4: Ожидание, что параллельный маршрут будет перерисовываться при каждой навигации по основному контенту.
Наоборот: параллельные маршруты сохраняют своё состояние и не сбрасываются без необходимости. Это их плюс, но иногда может сбить с толку.

Ошибка №5: Неправильная структура файлов.
Если вы случайно назовёте папку chat вместо @chat — это будет обычный вложенный маршрут, а не параллельный.

Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ