Next.js App Router 알아보기

JINJIN·2024년 4월 18일
1

Next.js

목록 보기
2/2
post-thumbnail

Next.js 13버전 이후로 새롭게 생긴 App router 방식에 대해 알아보겠습니다.

Next.js의 라우팅 방식

Next.js는 리액트 프레임워크로서 다양한 기능을 제공하고 있는데, 그중 가장 대표적인 것이 바로 라우팅입니다. 많은 프레임워크는 라우팅을 위해 디렉토리 구조와 파일 규칙을 강제합니다.

Next.js 역시 예전부터 라우팅을 위한 파일을 웹사이트 구조에 맞춰서 루트 디렉토리에 있는 pages라는 폴더 내부에 생성하도록 했습니다. (Page Router 방식)

pages 디렉토리 상위에 src 폴더가 추가되는 변경이 있기도 했지만, Next.js는 두 방식(src/pages/와 pages/)을 모두 허용했고, 이외에 규칙의 큰 변화는 없었습니다.


App Router

그러나 Next.js 13부터 App Router가 등장하며 Next.js의 라우팅 방식이 아예 달라졌습니다. 사실 Next.js 13.0에서는 베타로 소개되었기에, 실질적인 변화는 2023년 5월 초에 있었던 Next.js 13.4부터라고 봐야 할 것 같습니다. 이처럼 Next.js 13.4부터 프로젝트 생성 시 App Router가 기본 설정으로 적용되었으며, 라우팅의 많은 규칙이 달라졌습니다.


Page Router vs App Router

Next.js 13 이전에는 pages 디렉토리를 최상위 디렉토리로 가지고, 그 안에 파일들의 이름으로 url이 자동으로 라우팅되었습니다.

Next.js 13 부터 app 디렉토리를 최상위 디렉토리로 가지고, 모든 파일들이 자동으로 라우팅되는 것이 아니라, 폴더 안에 page.jsroute.js라는 파일명을 가진 파일들만 라우팅됩니다.


App Router 기능

Private Folders (비공개 폴더)

Private Folders 기능은 폴더 앞에 밑줄을 붙여 생성할 수 있습니다. _folderName

이는 해당 폴더가 비공개 구현 세부 사항임을 나타내며, 라우팅 시스템에 의해 고려되지 않아야 함을 의미하며, 따라서 해당 폴더와 그 모든 하위 폴더가 라우팅에서 제외됩니다.

주로 UI 로직과 라우팅 로직을 분리하기 위해 사용하는 기능입니다.


Route Groups (라우트 그룹)

Route Groups 기능은 폴더를 괄호로 감싸서 라우트 그룹을 생성할 수 있습니다. (folderName)
이는 해당 폴더가 조직적인 목적을 위한 것이며, 라우트의 URL 경로에 포함되어서는 안 된다는 것을 나타냅니다.

라우트 그룹은 라우트를 보다 체계적으로 관리하고, 특정 구조 내에서 중첩 레이아웃을 용이하게 구현할 수 있는 방법을 제공합니다, 이는 개발자가 더 정교하고 유연한 웹 애플리케이션 구조를 설계할 수 있게 해줍니다.


Pages 그리고 Layout

Pages

Pages는 특정 경로에 고유한 UI입니다. page.js 혹은 page.tsx 파일에서 컴포넌트를 기본으로 내보내서 페이지를 정의할 수 있습니다.

예를 들어, 인덱스 페이지를 생성하려면, 앱 디렉토리 안에 page.js 파일을 추가합니다.

// `app/page.js`
export default function Page() {
  return <h1>Hello, Home page!</h1>
}

다른 페이지를 생성하려면, 새 폴더를 만들고 그 안에 page.js 파일을 추가합니다. 예를 들어, /dashboard 경로에 대한 페이지를 생성하려면 dashboard라는 새 폴더를 만들고 그 안에 page.js 파일을 추가합니다.

  • 페이지에는 .js, .jsx, 또는 .tsx 파일 확장자를 사용할 수 있습니다.
  • 경로 세그먼트를 공개적으로 접근 가능하게 하려면 page.js 파일이 필요합니다.
  • 페이지는 기본적으로 서버 컴포넌트이지만, 클라이언트 컴포넌트로 설정될 수 있습니다.
  • 페이지는 데이터를 가져올 수 있습니다. (데이터 페칭)

Layout

Layout은 여러 경로 간에 공유되는 UI입니다. 탐색 시, 레이아웃은 상태를 유지하고, 상호작용이 가능하며, 재렌더링되지 않습니다. 레이아웃은 또한 중첩될 수 있습니다.

layout.js 파일에서 React 컴포넌트를 기본으로 내보내서 레이아웃을 정의할 수 있습니다. 이 컴포넌트는 렌더링 중에 하위 레이아웃(있는 경우)이나 페이지로 채워질 children prop을 받아야 합니다.

예를 들어, 레이아웃은 /dashboard/dashboard/settings 페이지와 공유될 것입니다.

export default function DashboardLayout({
  children, // 페이지 또는 중첩 레이아웃이 됩니다.
}) {
  return (
    <section>
      {/* 여기에 공유 UI 포함(예: Header 또는 Sidebar 등) */}
      <nav></nav>
      {children}
    </section>
  )
}


Root Layout (필수)

루트 레이아웃은 앱 디렉토리의 최상위 레벨에서 정의되며 모든 경로에 적용됩니다. 이 레이아웃은 필수이며, html과 body 태그를 포함해야 하며, 서버에서 반환된 초기 HTML을 수정할 수 있습니다.

// `app/layout.js`
export default function RootLayout({ children }) {
  return (
    <html lang="ko">
      <body>
        {/* Layout UI */}
        <main>{children}</main>
      </body>
    </html>
  )
}

중첩 레이아웃

기본적으로, 폴더 계층 구조에서의 레이아웃은 중첩되며, 이는 자식 레이아웃을 children prop을 통해 감싸는 것을 의미합니다. 특정 경로 세그먼트(폴더) 내부에 layout.js를 추가함으로써 레이아웃을 중첩시킬 수 있습니다.

예를 들어, /dashboard 경로에 대한 레이아웃을 생성하려면, dashboard 폴더 내부에 새로운 layout.js 파일을 추가합니다.

// `app/dashboard/layout.js`
export default function DashboardLayout({ children }) {
  return <section>{children}</section>
}

위의 두 레이아웃을 결합하면, 루트 레이아웃(app/layout.js)이 대시보드 레이아웃(app/dashboard/layout.js)을 감싸고, 대시보드 레이아웃은 app/dashboard/* 내부의 경로 세그먼트를 감싸게 됩니다.

그림으로 표현하면 두 레이아웃은 다음과 같이 중첩됩니다.

  • 레이아웃에는 .js, .jsx, 또는 .tsx 파일 확장자를 사용할 수 있습니다.
  • <html><body> 태그는 오직 루트 레이아웃에서만 포함될 수 있습니다.
  • 같은 폴더 내에 layout.jspage.js 파일이 정의되어 있을 때, 레이아웃은 페이지를 감쌉니다.
  • 레이아웃 또한 기본적으로 서버 컴포넌트이지만, 클라이언트 컴포넌트로 설정될 수 있습니다.
  • 레이아웃 또한 데이터를 가져올 수 있습니다. (데이터 페칭)
    부모 레이아웃과 그 자식 사이에 데이터를 전달하는 것은 불가능합니다. 그러나, 한 경로에서 같은 데이터를 여러 번 가져올 수 있으며, React는 성능에 영향을 주지 않으면서 요청을 자동으로 중복 제거합니다.
  • 레이아웃은 자신 아래의 경로 세그먼트에 접근할 수 없습니다. 모든 경로 세그먼트에 접근하기 위해서는 클라이언트 컴포넌트에서 useSelectedLayoutSegment 또는 useSelectedLayoutSegments를 사용할 수 있습니다.
  • 여러 루트 레이아웃을 생성하기 위해 경로 그룹을 사용할 수 있습니다. (하단 참조)

여러 루트 레이아웃 생성하기

여러 루트 레이아웃을 생성하려면, 최상위 레벨의 layout.js 파일을 제거하고, 각 경로 그룹 내에 layout.js 파일을 추가하면 됩니다.

이는 완전히 다른 UI나 경험을 가진 섹션으로 애플리케이션을 분할하는 데 유용합니다. <html><body> 태그는 각 루트 레이아웃에 추가되어야 합니다.

위 예시에서, (marketing)(shop)은 각각 자신의 루트 레이아웃을 가지고 있습니다.

profile
안녕하세요! 배우는 것을 좋아하는 개발자 JINJIN입니다.

0개의 댓글