본문 바로가기
프로그래밍/Next.js

NEXT.JS 중첩 라우팅(Nested Routing)과 레이아웃(Layout) 적용

by K-인사이터 2024. 4. 21.
반응형

안녕하세요 

K-인사이트입니다. 

 

 

웹 사이트에서 공통된 레이아웃을 유지하며 새로운 페이지들을 개발하는 것은 중요한 작업입니다. 페이지들이 기존 디자인을 훼손하지 않으면서도 각 페이지들을 개발하는 속도 및 효율성이 높아야 합니다. Next.js 는 이러한 기능을 제공하기 위해 매우 편리한 방식으로 라우트를 추가하고 기존 디자인을 계승해서 UI 를 개발하는 방법을 제공합니다. 이 시간에는 Next.js 의 기능을 통해 복잡한 구조의 라우팅을 구현하고 부분 렌더링, 루트 레이아웃 등을 배워보도록 하겠습니다. 

 

 

이전 글 바로가기 

이 글은 이어진 글입니다. 샘플 프로젝트를 다운로드 받아 환경을 구성해야 한다면 아래의 글을 통해 편리하게 실습 환경을 구성할 수 있습니다. 

https://k-in.tistory.com/203

 

NEXT.JS 일단 프로젝트부터 생성해서 공부해보자!

안녕하세요 K-인사이트입니다. Next.js 란? 기존 리액트에 없는 서버 사이드 렌더링(SSR,Server-Side Rendering), 정적 사이트 생성(SSG, Static Site Generation), 증분 정적 재생성(ISR, Incremental Static Regeneration)과

k-in.tistory.com

 

이 글에서 다루는 내용

Next.js 에서 레이아웃과 페이지를 생성하고 적용하는 방법을 배웁니다. 이 과정을 통해 앱에서 공통 레이아웃에 속하는 GNB, 네비게이션 사이드바 등을 구현하는 전체적인 틀을 잡을 수 있으며 Next.js 의 파일 시스템 기반 라우팅에 대해 배울 수 있습니다. 

  • 중첩 라우팅(Nested Routing)에 대한 이해
  • 파일 시스템 라우팅 기반의 신규 라우팅 생성 방법
  • 충접 레이아웃(Nested Layout)에 대한 이해 및 생성 방법
  • 루트 레이아웃(Root Layout)과 부분 렌더링(Partial Rendering)의 이해

중첩 라우팅이란?

Next.js 와 관련된 원문을 보게되면 nested 라는 단어가 많이 등장합니다. 이를 한글로 번역하면 "중첩"이라는 말로 번역되며 그 의미는 "거듭 겹치거나 포개어짐"이라는 뜻을 가집니다. 그렇다면 라우팅을 중첩하는 것은 무엇일까요? 이는 Next.js 의 파일시스템 기반 라우팅 구조와 관련이 깊습니다. 

 

아래의 그림을 보면 app, app/dashboard, app/dashboard/invoices 파일 구조가 보입니다. 이 폴더들의 구조는 그대로 URL Path 에 1:1로 맵핑됩니다. 즉, Next.js 의 파일시스템 기반 라우팅 메커니즘에 의해 폴더 구조가 거듭 포개어지면서 URL Path 가 생성됨을 말합니다. 이러한 구조는 단순히 폴더를 생성함으로써 URL 경로를 자동으로 생성할 수 있어 개발 생산성 향상에 도움이되며 코드베이스를 분석할때도 도움이됩니다. 

 

 

그렇다면, 단순히 폴더만 생성한다고 웹페이지가 그려질까요? 아닙니다. 일반적으로 프로젝트 내에서는 여러 폴더들을 생성하고 그 용도가 꼭 웹페이지를 렌더링하기 위한 용도로 국한되지 않습니다. Button 과 같은 UI 컴포넌트, 데이터를 처리하기 위한 유틸리티등 다양한 용도의 코드들이 존재합니다. 따라서 폴더와 URL Path 를 1:1로 맵핑하더라도 특별한 규칙을 통해 혼선이 발생되지 않도록 방지해야 합니다. Next.js 에서 파일 시스템 기반 라우팅을 위한 특별한 규칙들은 다음과 같습니다. 

 

  • 라우팅 폴더는 app 폴더의 하위 폴더이어야 함. 
  • 라우팅 폴더를 접근하도록 하기 위해서는 page.js 또는 page.tsx 파일이 필요함.
  • 각 폴더 이름은 URL 경로의 이름이 됨.

조금 복잡한 내용인듯 하지만 쉽게 말해 파일 시스템 구조가 URL Path 경로에 맵핑되는 메커니즘을 말합니다. 아래의 그림을 조금 어렵게 설명했다고 생각하면 됩니다. 

 

 

라우팅 실습. 대시보드 페이지 생성 

앱 내에 'dashboard' 폴더를 생성하고 'page.tsx' 파일을 만듭니다. 'tsx' 파일에는 아래의 코드를 작성합니다. npm run dev 명령어를 실행중인 경우, 바로 http://localhost:3000/dashboard로 이동해서 페이지가 생성된 것을 확인할 수 있습니다.

export default function Page() {
  return <p>Dashboard Page</p>;
}

 

/dashboard 경로는 dashboard 폴더 아래에 page.tsx 파일을 생성하여 만들 수 있습니다. 그렇다면 ui 폴더나 lib 폴더에도 접근할 수 있을까요? 아닙니다. Next.js는 UI 컴포넌트, 테스트 파일 등의 관련 코드를 라우트 경로 안에 둘 수는 있지만, 페이지 파일만 접근 가능하도록 제한하여 다른 파일들에 대한 접근을 방지합니다.

 

 

여기에 customers, invoices 폴더를 dashboard 하위 경로로 두는 것이 가능합니다. 아래와 같이 dashboard 폴더 아래에 원하는 경로이름과 대응하는 폴더를 생성하고 page.tsx 파일을 생성하면 구현됩니다. 아래의 두 경로를 생성하는 실습을 해볼까요? 

  • http://localhost:3000/dashboard/invoices
  • http://localhost:3000/dashboard/customers

 

라우팅 실습.  대시보드 레이아웃 생성

Next.js에서는 특별한 layout.tsx 파일을 사용하여 여러 페이지 간에 공유되는 UI를 만들 수 있습니다. 대시보드 페이지의 레이아웃을 만들어 보겠습니다. 이 레이아웃은 dashboard 폴더 하위의 customers, invoices 에도 동일하게 적용됩니다. 대시보드 폴더에 layout.tsx라는 새 파일을 추가하고 다음 코드를 붙여넣습니다.

import SideNav from '@/app/ui/dashboard/sidenav';
 
export default function Layout({ children }: { children: React.ReactNode }) {
  return (
    <div className="flex h-screen flex-col md:flex-row md:overflow-hidden">
      <div className="w-full flex-none md:w-64">
        <SideNav />
      </div>
      <div className="flex-grow p-6 md:overflow-y-auto md:p-12">{children}</div>
    </div>
  );
}

 

 

위 코드의 역할은 간단합니다. 대시보드(dashboard) 경로 하위에 위치할 다른 라우팅들에 대한 공통된 UI를 제공합니다. 즉, 대시보드 및 커스토머(customers) 등에 접근하면 레이아웃 파일에서 지정한 SideNav 등의 컴포넌트들이 유지됩니다. layout.tsx 파일의 코드를 보면 children 속성을 인자로 받음을 알 수 있습니다. child 는 페이지나 혹은 또다른 layout 이 됩니다. 다시말해 SideNav 컴포넌트가 인보이스, 커스토머에도 적용됨을 말합니다. 아래 그림은 대시보드 폴더에서 정의한 레이아웃 파일이 어떻게 적용되는지를 보여줍니다. 그림의 화살표는 레이아웃 파일이 적용되는 파일을 의미합니다. 

 

위 레이아웃 파일은 네비게이션 사이드바 기능을 제공합니다. 구현된 기능은 렌더링되어 아래처럼 표시됩니다. 

 

 

Next.js 는 Partial Rendering 을 지원합니다. 따라서 라우팅이 변경될 시에 페이지 컴포넌트만 업데이트 됩니다. 아래의 그림을 통해 쉽게 이해할 수 있습니다. 

 

루트 레이아웃이란? 

앞서 Next.js 폰트를 다루면서 app/layout.tsx 파일을 변경하였습니다.  app 폴더 내 최상위에 위치하는 layout.tsx 파일을 루트 레이아웃이라고 부릅니다. 루트 레이아웃에 추가되는 모든 UI 는 어플리케이션의 모든 페이지들에 공통적으로 적용됩니다. 따라서, html 또는 body 태그나 metadata 정도를 추가할 수 있습니다. 

import '@/app/ui/global.css';
import { inter } from '@/app/ui/fonts';
 
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body className={`${inter.className} antialiased`}>{children}</body>
    </html>
  );
}

 

 

이상입니다.

K-인사이트 올림.

반응형