본문 바로가기

넥스트

[next.js] 8. 병렬 라우팅

반응형
next.js 공식 문서를 번역한 내용을 토대로 공부한 자료입니다. 자세한 내용은 공식 사이트를 참고 해주세요.

  병렬 경로

병렬 라우팅을 사용하면 동일한 레이아웃에서 하나 이상의 페이지를 동시에 또는 조건부로 렌더링할 수 있습니다. 대시보드 및 소셜 사이트의 피드와 같이 매우 동적인 앱 섹션의 경우 병렬 라우팅을 사용하여 복잡한 라우팅 패턴을 구현할 수 있습니다.

 

예를 들어 팀 페이지와 분석 페이지를 동시에 렌더링할 수 있습니다.

 
https://nextjs.org/docs/app/building-your-application/routing/parallel-routes
 

병렬 라우팅을 사용하면 경로가 독립적으로 스트리밍될 때 각 경로에 대해 독립적인 오류 및 로드 상태를 정의할 수 있습니다.

 

https://nextjs.org/docs/app/building-your-application/routing/parallel-routes

 
병렬 라우팅을 사용하면 인증 상태와 같은 특정 조건에 따라 슬롯을 조건부로 렌더링할 수도 있습니다. 이를 통해 동일한 URL에서 완전히 분리된 코드를 사용할 수 있습니다.
(개인정리) 경로가 독립적이라는 말은 하나의 루트 경로에서 페이지가 서로 분리되어 경로가 나뉜다는 것을 의미하는 듯하다. 이는 폴더로 라우트 경로를 /board 혹은 /service 와 같이 분리하는 개념이 아니라, /  이라는 루트 경로에서 마치 하나의 화면에 두 개의 페이지가 렌더링되는 것과 같다.

이를 병렬 라우팅이라 하고, 병렬 라우팅을 이용하면, 예를 들어 유저가 특정한 서비스에 대한 권한이 있고, 없고에 따라서 두 개의 독립된 페이지 중에서 하나를 보여줄 수도 있고, 두 페이지 모두를 하나의 레이아웃에서 보여줄 수도 있는 독립적인 처리가 가능하다고 이해할 수 있다. 이러한 분리 처리는 각 분리된 페이지에 대한 에러처리 및 로딩 처리에도 동일하게 적용된다.
 
 

  협약

병렬 경로는 명명된 슬롯 사용하여 생성됩니다 . 슬롯은 규칙에 따라 정의되며 @folderprops와 동일한 수준의 레이아웃에 전달됩니다.

 

- 슬롯은 경로 세그먼트가 아니며 URL 구조에 영향을 주지 않습니다 . 파일 경로는 /@team/members에서 액세스할 수 있습니다

 

예를 들어, 다음 파일 구조는 두 개의 명시적 슬롯인 @analytics @team 를 정의합니다 

 

 

위의 폴더 구조는 이제 app/layout.js의 구성 요소가 @analytics, @teamchildren 슬롯 소품을 허용하고 소품과 함께 병렬로 렌더링할 수 있음을 의미합니다. 

 

app/layout.tsx
export default function Layout(props: {
  children: React.ReactNode // 기존의 하위 컴포넌트 및 하위 레이아웃 컴포넌트 등
  analytics: React.ReactNode // 슬릇으로 생성된 새로운 하위 컴포넌트 및 레이아웃 컴포넌트 등
  team: React.ReactNode       // 이하동문
}) {
  return (
    <>
      {props.children}
      {props.team}     
      {props.analytics}
    </>
  )
}

 

* 알아두면 좋은 점 : children prop은 폴더에 매핑할 필요가 없는 암시적 슬롯입니다. app/page.js 이는app/@children/page.js. 와 동일하다는 의미 입니다 

(개인정리) @규칙명 과 같이 입력하여 생성된 여러 슬릇들은  정의된 페이지, 로딩,에러 컴포넌트들이 같은 루트 경로의 페이지 내에서 일부분으로 포함되며, 병렬적으로 각각 독립적인 처리가 가능한 페이지 안의  페이지가 된다고 이해할 수 있다.

추가로 children prop (기존의 자식 컴포넌트들)은 암시적 슬릇이므로 @children 으로 정의된 슬릇이다. 단 폴더에 매핑할 필요가 없기에 암시적으로 표현된다.

 

비교할 수 없는 경로

기본적으로 슬롯 내에서 렌더링되는 콘텐츠는 현재 URL과 일치합니다. 일치하지 않는 슬롯의 경우,  Next.js가 렌더링하는 콘텐츠는 라우팅 기술과 폴더 구조에 따라 다릅니다.

 

  default.js

Next.js가 현재 URL을 기반으로 슬롯의 활성 상태를 복구할 수 없는 경우 대체 파일로 렌더링할 파일을 정의할 수 있습니다 .

 

다음 폴더 구조를 고려하세요. 슬롯 @team에는 디렉토리가 settings이 있지만  @analytics 디렉토리는 없습니다.

 
 
(개인 정리) 슬릇으로 생성된 디렉토리는  default.js 파일을 생성하는 경우 슬릇으로 정의된 디렉토리의  page.js 가 예상치 못한 문제로 렌더링되지 못하는 경우 이를 대체하는 파일로 default.js 컴포넌트를 렌더링한다. 
 

탐색 시 Next.js는 현재 URL과 일치하지 않더라도 슬롯의 이전 활성 상태를 렌더링합니다.

 

새로고침

다시 로드할 때 Next.js는 먼저 일치하지 않는 슬롯의 default.js 파일을 렌더링하려고 합니다. 사용할 수 없는 경우 404가 렌더링됩니다.

 

일치하지 않는 경로에 대한 404는 병렬 렌더링되어서는 안 되는 경로를 실수로 렌더링하지 않도록 하는 데 도움이 됩니다.

 

  useSelectedLayoutSegment

useSelectedLayoutSegment 및  useSelectedLayoutSegmentsa 둘 다 parallelRoutesKey 를 허용하면 해당 슬롯 내의 활성 경로 세그먼트를 읽을 수 있습니다.

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

사용자가 URL 표시줄에서 @auth/login 또는 /login으로 이동하면 loginSegments는 문자열 "login"과 동일합니다.

 

  예시

     모달

병렬 라우팅을 사용하여 모달을 렌더링할 수 있습니다.

슬롯 @auth 은 일치하는 경로(예: /login)로 이동하여 표시할 수 있는 <Modal> 구성 요소를 렌더링합니다 .

export default async function Layout(props: {
  // ...
  auth: React.ReactNode
}) {
  return (
    <>
      {/* ... */}
      {props.auth}
    </>
  )
}
(개인정리) @auth 라는 슬릇을 생성하고, 해당 슬릇 디렉토리에 page.js 파일을 만들어 모달 ui 를 작성해둔 후, layout 컴포넌트의 매개변수로 받은 props의 속성으로 auth 슬릇에 접근하면, 해당 슬릇 디렉토리에서 생성한 모달을 렌더링할 수 있다.

 

app/@auth/login/page.tsx()

import { Modal } from 'components/modal'
 
export default function Login() {
  return (
    <Modal>  // 모달 컴포넌트 내에 jsx 요소들은 모달 컴포넌트의 props 에 children 이름으로 담긴다.
      <h1>Login</h1>
      {/* ... */}
    </Modal>
  )
}

modal이 활성화되어 있지 않을 때 modal의 내용이 렌더링되지 않도록 하려면 null을 반환하는 default.js 파일을 만들 수 있습니다.

 
app/@auth/default.tsx
export default function Default() {  return null}
(개인정리) 모달이 활성화 되어 있지 않을 때 내용이 안 보이게 하려면 null 을 반환하는 default.js 파일을 생성할 수 있다.

 

    모달닫기

Link href="/modal">을 사용하여 클라이언트 탐색을 통해 모달이 시작된 경우 router.backmodal을 호출하거나 Link 구성 요소를 사용하여 모달을 해제할 수 있습니다.

 
app/@auth/login/page.tsx
'use client'

import { useRouter } from 'next/navigation'
import { Modal } from 'components/modal'
 
export default async function Login() {
  const router = useRouter()
  return (
    <Modal>
      <span onClick={() => router.back()}>Close modal</span>
      <h1>Login</h1>
      ...
    </Modal>
  )
}

모달에 대한 자세한 내용은 Intercepting Routes 섹션 에서 다룹니다 (https://nextjs.org/docs/app/building-your-application/routing/intercepting-routes).

 

Routing: Intercepting Routes | Next.js

Intercepting routes allows you to load a route from another part of your application within the current layout. This routing paradigm can be useful when you want to display the content of a route without the user switching to a different context. For examp

nextjs.org

 

 

다른 곳을 탐색하고 모달을 닫으려는 경우 캐치올(catch-all) 경로를 사용할 수도 있습니다.

 
app/@auth/[...catchAll]/page.tsx
export default function CatchAll() {  return null}
(개인정리) catch-all 을 활용하면, 동적 경로에 일치하지 않는 이 외의 경로에 대한 예외적인 페이지 처리를 실시할 수 있다. 예를 들어 지정한 경로 정보가 존재하지 않는 경우에는 catch-all 로 지정한 page.js 컴포넌트가 렌더링 되도록 할 수 있다. 활용 예시로는 error.js 를 대신하여 페이지 자체에 대한 404 에러 페이지를 보여줄 수 있다.

 

  조건부 경로

병렬 경로를 사용하여 조건부 라우팅을 구현할 수 있습니다. 예를 들어 인증 상태에 따라 @dashboard또는 @login 라우팅을 렌더링할 수 있습니다. 

 
APP/layout.tsx
import { getUser } from '@/lib/auth'
 
export default function Layout({
  dashboard,
  login,
}: {
  dashboard: React.ReactNode
  login: React.ReactNode
}) {
  const isLoggedIn = getUser()
  return isLoggedIn ? dashboard : login
}
 

 

(개인정리) 위와 같이 병렬 라우팅을 활용하면, 로그인 유저 정보가 존재한다면 dashboard 슬릇의 페이지 컴포넌트를 렌더링하고, 유저 정보가 없다면 login 슬릇의 페이지 컴포넌르를 렌더링하도록 지정할 수 있다.
반응형

'넥스트' 카테고리의 다른 글

[next.js] 10. 미들웨어  (0) 2023.09.02
[next.js] 9. 경로 가로채기  (0) 2023.08.31
[next.js] 7. 에러 핸들링  (2) 2023.08.28
[next.js] 6. 로딩 UI 와 스트리밍  (0) 2023.08.27
[next.js] 5. 동적 라우팅  (0) 2023.08.27