평행 루트는 동일한 뷰 안에서 독립적으로 네비게이팅할 수 있는 하나 또는 여러 페이지들을 동시에 렌더할 수 있도록 도와줍니다. 대시보드나 소셜 사이트의 피드 같은, 높은 동적 요소들로 구성된 애플리케이션의 경우, 복잡한 라우팅 패턴을 도입하는 데에 이용될 수 있습니다.
평행 루트는 슬롯을 이용해 생성할 수 있습니다. 슬롯은 @폴더이름 컨벤션을 이용해 정의될 수 있습니다.
예를 들어, 아래의 파일 구조는 비디오 통계 대시보드를 위해 @audience와 @views라는 두 개의 명료한 슬롯을 정의합니다.
dashboard
├── @audience
│ ├── demographics
│ │ └── page.js
│ ├── subscribers
│ │ └── page.js
│ └── page.js
├── @views
│ ├── impressions
│ │ └── page.js
│ ├── view-duration
│ │ └── page.js
│ └── page.js
├── layout.js
└── page.js
위의 폴더 스트럭쳐는 /dashboard/layout.js레이아웃 컴포넌트가 children prop과 함께 병렬로 @audience와 @views슬롯을 props으로 받아, 평행적으로 렌더할 수 있음을 뜻합니다:
// app/dashboard/layout.tsx
function AudienceNav() {
return <nav>...</nav>
}
function. ViewsNav() {
return <nav>...</nav>
}
export default function Layout({
children,
audience,
views,
}: {
children: React.ReactNode,
audience: React.ReactNode,
views: React.ReactNode,
}) {
return (
<>
<h1>Tab Bar Layout</h1>
{children}
<h2>Audience</h2>
<AudienceNav />
{audience}
<h2>Views</h2>
<ViewsNav />
{views}
</>
);
}
알아두면 좋은 것:
children prop은 폴더에 매핑될 필요가 없는 명료한 슬롯입니다. 이는 dashboard/page.js는 dashboard/@children/page.js와 동일하다는 뜻입니다.슬롯은 URL 구조에 영향을 주지 않습니다. /dashboard/@audience/subscribers는 /dashboard/subscribers로 접근 가능합니다.
(soft navigation을 이용하여) 이전 혹은 다음으로 네비게이션 할 때, URL이 업데이트 되고 브라우저는 이전에 활성화된 슬롯을 복원할 겁니다.
예를 들어서, 만약 유저가 /dashboard/subscribers로 이동하고, 그 다음에 /dashboard/impressions로 이동하면, 이전으로 이동했을 때 URL은 dashboard/subscribers로 업데이트 될 겁니다.
default.js새로고침하는 경우 (또는 hard navigation의 경우), 브라우저는 현재의 URL에 맞는 슬롯을 렌더하지만, 다른 평행 슬롯이 활성화 되어있었는지는 알 수 없습니다.
default.js파일을 정의하여 브라우저가 이전의 상태를 복원할 수 없을 때 폴백으로 렌더할 수 있습니다.
dashboard
├── @team
│ └── ...
├── @user
│ └── ...
├── default.js
├── layout.js
└── page.js
평행 루트는 조건부 라우팅을 도입하기 위해 사용될 수 있습니다. 예를 들어, 현재의 유저 타입에 기반하여 @user이나 @team루트를 렌더할 수 있습니다.
// app/dashboard/layout.tsx
import { getCurrentUserType } from 'lib/user';
export default async function Layout({
children,
user,
team,
}: {
children: React.ReactNode;
user: React.ReactNode;
team: React.ReactNode;
}) {
const userType: 'user' | 'team' = getCurrentUserType();
return (
<>
{/* 현재의 유저 타입에 기반하여 user 또는 team 슬롯을 렌더함 */
{userType === 'user' ? user : team}
{children}
</>
);
}