회사에서 대시보드 메인페이지를 구현해야 하는데, 이 메인페이지에서 여러가지 차트 블록이 있고 이 블록마다 데이터 패칭을 각각 해주어야 하는 상황이다.
대시보드 메인페이지 한 라우트 안에서 저 패칭이 모두 일어난다면 상태관리도 복잡해질 뿐더러 더러운 코드가 될 것 같다고 생각했다.
공식문서를 보니 Parallel Routes라는 방식을 알게 됐고, 해법이 될 수 있을 것 같아서 학습해보았다.
병렬 라우팅을 사용해 동일한 레이아웃에서 하나 이상의 페이지를 동시 또는 조건부로 렌더링이 가능하다. 앱에서 대시보드나 피드처럼 매우 동적인 섹션에서 유용하다.

예시처럼 대시보드에서 team과 analytics 페이지를 동시에 렌더링 할 수 있다.
병렬 라우트는 slots을 이용하는데 slot이란 @folder 컨벤션으로 정의된 것이다.

위는 @analytics와 @team slot이 정의된 것이다.
slots은 공유된 부모 레이아웃에 props로 들어간다. 위 예시에서는 @analytics와 @team slot을 app/layout.ts 에서 props로 전달 받는다. children prop과 함께 병렬적으로 렌더링 될 수 있다.
export default function Layout({
children,
team,
analytics,
}: {
children: React.ReactNode
analytics: React.ReactNode
team: React.ReactNode
}) {
return (
<>
{children}
{team}
{analytics}
</>
)
}
참고로 slot은 route segement가 아니기 때문에 URL 구조에 영향을 끼치지 않는다. 예를 들어 /@analytics/views는 /views로 URL이 정해진다.

ㄴroute segment에 대한 그림
기본적으로 Next.js는 각각의 slot에 대해 active state 를 추적하고 있다. 하지만 slot에서 렌더되는 콘텐츠는 네비게이션의 타입에 의존하고 있다.
active State란 사용자가 특정 페이지나 컴포넌트를 보고 있는 상태를 말한다.
Soft Navigation : 클라이언트 사이드 네비게이션에서 Next.js는 부분적인 slot 내에서 서브페이지를 바꾸는 부분적인 렌더를 진행한다. 이때 다른 slot은 active를 유지한다.
Hard Navigation : 전체 페이지 로드 후 (브라우저 새로고침) Next.js는 현재 URL과 매칭되지 않는 slot들의 active state 를 결정하지 못한다. 대신에 매칭되지 않은 slot들은 default.js 을 렌더한다. 만약 default.js 가 없다면 404를 반환한다.
default.js 파일은 최초 로드나 새로고침 시 매칭되지 않은 slot에 대한 fallback 렌더파일이라고 생각하면 된다.

사진에서 @team 은 /settings 를 가지고 있지만 @analytics는 가지고 있지 않다. 이 상황에서 /settings 로 네비게이트 하면 @team slot은 /settings 페이지를 렌더하지만 @analytics는 default.js 를 보여줄 것이다.
또한 children은 묵시적인 slot이기 때문에 Next.js가 부모 페이지의 active state를 복구할 수 없는 경우 children의 기본 fallback으로 default.js파일을 생성해야 한다.
parallelRoutesKey를 파라미터로 받는다. 이 파라미터는 slot 내에 active route segement를 읽는다.
'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 롤 간에 다른 대시보드 페이지를 보여준다.

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.js를 slot 내부에 넣어 유저가 slot을 독립적으로 네비게이트할 수 있도록 한다.

예를 들어, @analytics 는 /page-views와 /visitors 두 가지 서브 페이지를 가진다.
//app/@analytics/layout.tsx
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>
</>
)
}
@analytics 내부에 layout 파일을 만들어 두 페이지간 탭을 공유한다.
공식문서 링크
Intercepting Routes와 함꼐 사용되어 모달을 구현할 수 있다. 이는 우리가 모달을 만들 때 겪었던 몇 가지 어려움들을 해결해준다
이 내용으로 미루어보아 폼형식, 특정 데이터를 띄워주는 모달에서 활용하면 좋겠다는 생각이 들었다.
그냥 경고나, 확인용도의 모달의 경우는 여러 컴포넌트에서 활용되다보니 라우터로 관리하면 오히려 복잡할 것 같다는 생각이 들었고 굳이 저 기능들이 필요로 하진 않은 것 같았다.
모달에 관해서는 intercepting routes 개념 또한 필요로 하여 다음 포스트에서 다뤄보도록 하겠다!
병렬적 라우트는 독립적인 에러와 로딩을 각 라우트마다 가능하도록 한다.

이를 활용한다면, 대시보드 차트 블록마다 데이터 패칭의 상태가 어떤지 다른 차트 블록에 영향받지 않고 보여줄 수 있을 것 같아서 꼭 도입해봐야겠다!
https://www.youtube.com/watch?v=wi8kF8UniUI
위 유튜버가 아주 잘 예제코드를 설명해주어서 스택블리츠로 따라 구현해보았다.
스택블리츠 코드