Spec-Zone.ru › Next.js

Параллельные маршруты

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

Например, рассматривая панель мониторинга, вы можете использовать параллельные маршруты для одновременного отображения страниц team и analytics:

Parallel Routes DiagramParallel Routes Diagram

Слоты

Параллельные маршруты создаются с использованием именованных слотов. Слоты определяются с использованием соглашения @folder. Например, следующая структура файлов определяет два слота: @analytics и @team:

Parallel Routes File-system StructureParallel Routes File-system Structure

Слоты передаются как свойства родительскому макету. В примере выше, компонент в app/layout.js теперь принимает свойства слотов @analytics и @team и может отображать их параллельно вместе со свойством children:

export default function Layout({
  children,
  team,
  analytics,
}: {
  children: React.ReactNode
  analytics: React.ReactNode
  team: React.ReactNode
}) {
  return (
    <>
      {children}
      {team}
      {analytics}
    </>
  )
}

Однако, слоты не являются сегментами маршрута и не влияют на структуру URL. Например, для /@analytics/views, URL будет /views, так как @analytics является слотом.

Важно знать:

  • Свойство children является неявным слотом, который не нужно сопоставлять с папкой. Это означает, что app/page.js эквивалентно app/@children/page.js.

Активное состояние и навигация

По умолчанию, Next.js отслеживает активное состояние (или подстраницу) для каждого слота. Однако содержимое, отображаемое в слоте, будет зависеть от типа навигации:

  • Мягкая навигация: Во время навигации на стороне клиента Next.js выполнит частичное рендеринг, изменив подстраницу в слоте, сохранив при этом активные подстраницы других слотов, даже если они не соответствуют текущему URL.
  • Жесткая навигация: После полной загрузки страницы (обновление браузера), Next.js не может определить активное состояние для слотов, не соответствующих текущему URL. Вместо этого он отобразит файл default.js для несоответствующих слотов или 404 если default.js не существует.

Важно знать:

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

default.js

Вы можете определить файл default.js для рендеринга по умолчанию в качестве резервного варианта для несоответствующих слотов во время начальной загрузки или полной перезагрузки страницы.

Рассмотрите следующую структуру папок. У слота @team есть страница /settings, но у слота @analytics нет.

Parallel Routes unmatched routesParallel Routes unmatched routes

При переходе по /settings, слот @team отобразит страницу /settings, сохранив при этом текущую активную страницу для слота @analytics.

При обновлении Next.js отобразит default.js для @analytics. Если default.js не существует, вместо него отображается 404.

Кроме того, так как children является неявным слотом, вам также необходимо создать файл default.js для рендеринга резервного варианта для children, когда Next.js не может восстановить активное состояние родительской страницы.

useSelectedLayoutSegment(s)

Как useSelectedLayoutSegment, так и useSelectedLayoutSegments принимают параметр parallelRoutesKey, что позволяет считывать активный сегмент маршрута внутри слота.

'use client'
 
import { useSelectedLayoutSegment } from 'next/navigation'
 
export default function Layout({ auth }: { auth: React.ReactNode }) {
  const loginSegment = useSelectedLayoutSegment('auth')
  // ...
}

Когда пользователь переходит по app/@auth/login (или /login в адресной строке), loginSegment будет равно строке "login".

Примеры

Условные маршруты

Вы можете использовать Параллельные Маршруты для условного отображения маршрутов в зависимости от определенных условий, например, роли пользователя. Например, для отображения другой страницы панели мониторинга для ролей /admin или /user:

Conditional routes diagramConditional routes diagram
import { checkUserRole } from '@/lib/auth'
 
export default function Layout({
  user,
  admin,
}: {
  user: React.ReactNode
  admin: React.ReactNode
}) {
  const role = checkUserRole()
  return <>{role === 'admin' ? admin : user}</>
}

Группы вкладок

Вы можете добавить layout внутри слота, чтобы пользователи могли перемещаться по слоту независимо. Это полезно для создания вкладок.

Например, у слота @analytics есть две подстраницы: /page-views и /visitors.

Analytics slot with two subpages and a layoutAnalytics slot with two subpages and a layout

Внутри @analytics, создайте файл layout для совместного использования вкладок между двумя страницами:

import Link from 'next/link'
 
export default function Layout({ children }: { children: React.ReactNode }) {
  return (
    <>
      <nav>
        <Link href="/page-views">Page Views</Link>
        <Link href="/visitors">Visitors</Link>
      </nav>
      <div>{children}</div>
    </>
  )
}

Модальные окна

Параллельные Маршруты могут использоваться совместно с Маршрутами Перехвата для создания модальных окон. Это позволяет решить распространённые проблемы при создании модальных окон, такие как:

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

Рассмотрите следующую схему пользовательского интерфейса, где пользователь может открыть модальное окно входа из макета с помощью навигации на стороне клиента или получить доступ к отдельной странице /login:

Parallel Routes DiagramParallel Routes Diagram

Для реализации этой схемы начните с создания маршрута /login, который отображает главную страницу входа.

Parallel Routes DiagramParallel Routes Diagram
import { Login } from '@/app/ui/login'
 
export default function Page() {
  return <Login />
}

Затем, внутри слота @auth добавьте файл default.js, который возвращает null. Это гарантирует, что модальное окно не будет отображаться, когда оно не активно.

export default function Default() {
  return null
}

Внутри вашего слота @auth перехватите маршрут /login, обновив папку /(.)login Импортируйте компонент <Modal> и его дочерние элементы в файл /(.)login/page.tsx:

import { Modal } from '@/app/ui/modal'
import { Login } from '@/app/ui/login'
 
export default function Page() {
  return (
    <Modal>
      <Login />
    </Modal>
  )
}

Важно знать:

  • Соглашение, используемое для перехвата маршрута, например, (.), зависит от структуры вашей файловой системы. См. Соглашение о перехвате маршрутов.
  • Разделив функциональность <Modal> от содержимого модального окна (<Login>), вы можете убедиться, что любое содержимое внутри модального окна, например, формы, являются компонентами сервера. См. Взаимодействие клиентских и серверных компонентов для получения дополнительной информации.

Открытие модального окна

Теперь вы можете использовать маршрутизатор Next.js для открытия и закрытия модального окна. Это гарантирует, что URL будет правильно обновлен при открытии модального окна и при навигации назад и вперёд.

Для открытия модального окна передайте слот @auth как свойство родительскому макету и отобразите его вместе со свойством children.

import Link from 'next/link'
 
export default function Layout({
  auth,
  children,
}: {
  auth: React.ReactNode
  children: React.ReactNode
}) {
  return (
    <>
      <nav>
        <Link href="/login">Open modal</Link>
      </nav>
      <div>{auth}</div>
      <div>{children}</div>
    </>
  )
}

Когда пользователь нажимает на <Link>, откроется модальное окно вместо перехода на страницу /login. Однако при обновлении или начальной загрузке переход по /login перенаправит пользователя на главную страницу входа.

Закрытие модального окна

Вы можете закрыть модальное окно, вызвав router.back() или используя компонент Link.

'use client'
 
import { useRouter } from 'next/navigation'
 
export function Modal({ children }: { children: React.ReactNode }) {
  const router = useRouter()
 
  return (
    <>
      <button
        onClick={() => {
          router.back()
        }}
      >
        Close modal
      </button>
      <div>{children}</div>
    </>
  )
}

При использовании компонента Link для перехода с страницы, на которой не должен отображаться слот @auth больше, мы используем универсальный маршрут, который возвращает null.

import Link from 'next/link'
 
export function Modal({ children }: { children: React.ReactNode }) {
  return (
    <>
      <Link href="/">Close modal</Link>
      <div>{children}</div>
    </>
  )
}
export default function CatchAll() {
  return null
}

Важно знать:

  • Мы используем универсальный маршрут в нашем слоте @auth для закрытия модального окна из-за поведения, описанного в разделе Активное состояние и навигация. Поскольку навигация на стороне клиента на маршрут, который больше не соответствует слоту, останется видимым, нам нужно сопоставить слот с маршрутом, который возвращает null для закрытия модального окна.
  • Другие примеры могут включать открытие модального окна фото в галерее, а также наличие отдельной страницы /photo/[id] или открытие корзины покупок в боковом модальном окне.
  • Посмотреть пример модальных окон с перехваченными и параллельными маршрутами.

Отображение состояния загрузки и ошибок

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

Parallel routes enable custom error and loading statesParallel routes enable custom error and loading states

См. документацию Отображение состояния загрузки и Обработка ошибок для получения дополнительной информации.

© 2024 Vercel, Inc.
Licensed under the MIT License.
https://nextjs.org/docs/app/building-your-application/routing/parallel-routes

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API