icon

안동민 개발노트

4장 : 라우팅 심화

동적 라우트 생성


이전 장에서는 정적인 URL 경로를 가진 페이지를 만들고 연결하는 방법을 배웠습니다. 하지만 실제 서비스에서는 URL 일부가 데이터에 따라 동적으로 바뀌는 경우가 훨씬 많습니다.

예를 들어 블로그 상세(/blog/nextjs-basics), 상품 상세(/products/luxury-watch-xyz), 사용자 프로필(/users/alice) 같은 경로가 대표적입니다.

Next.js App Router는 이러한 요구사항을 충족시키기 위해 동적 라우트(Dynamic Routes) 기능을 제공합니다. 이 절에서는 동적 라우트를 생성하고, URL에서 동적인 값을 추출하여 페이지 컴포넌트에서 사용하는 방법에 대해 자세히 알아보겠습니다.


동적 라우트의 개념과 필요성

정적 라우트가 /about이나 /dashboard/settings처럼 고정된 URL을 가진다면, 동적 라우트는 URL의 특정 부분이 변수처럼 작동합니다.

  • 블로그 게시물: /blog/my-first-post, /blog/nextjs-deep-dive
  • 상품 상세: /products/12345, /products/67890
  • 사용자 프로필: /users/john-doe, /users/jane-smith

이러한 URL들은 /blog/, /products/, /users/는 고정되어 있지만, 그 뒤의 my-first-post, 12345, john-doe와 같은 값은 각 항목에 따라 달라집니다. Next.js는 이 동적인 부분을 감지하고, 해당 값을 페이지 컴포넌트로 전달하여 우리가 각기 다른 콘텐츠를 렌더링할 수 있도록 돕습니다.


동적 라우트 생성하기: 대괄호 [] 사용

Next.js App Router에서 동적 라우트 세그먼트를 정의하려면, 폴더 이름을 대괄호([])로 감쌉니다. 이 대괄호 안의 이름이 파라미터(Parameter)의 키(key)가 됩니다.

예를 들어, 블로그 게시물 상세 페이지를 만든다고 가정해 봅시다.

src/app/blog 폴더 생성: 먼저 src/app 안에 blog 폴더를 생성합니다. (만약 없다면)

...

[slug] 폴더 생성: src/app/blog 안에 [slug]라는 이름의 폴더를 생성합니다. 여기서 slug는 동적인 값이 들어갈 파라미터의 이름이 됩니다.

...

page.tsx 파일 생성: src/app/blog/[slug] 폴더 안에 page.tsx 파일을 생성합니다.

page.tsx
...

src/app/blog/[slug]/page.tsx 파일 내용 작성: 이 page.tsx 컴포넌트는 params라는 prop을 통해 URL에서 추출된 동적인 값을 전달받습니다.

src/app/blog/[slug]/page.tsx
// src/app/blog/[slug]/page.tsx

interface BlogDetailPageProps {
  params: {
    slug: string; // [slug] 폴더 이름과 일치해야 합니다.
  };
}

// 서버 컴포넌트로 작동하며, params를 prop으로 받습니다.
export default function BlogDetailPage({ params }: BlogDetailPageProps) {
  const { slug } = params; // URL에서 slug 값을 추출

  // 실제 애플리케이션에서는 이 slug 값을 사용하여
  // 데이터베이스나 API에서 해당 게시물의 내용을 불러올 것입니다.
  // 예: const post = await getPostBySlug(slug);

  return (
    <div>
      <h1>블로그 게시물: {slug}</h1>
      <p>
        현재 보고 계신 게시물의 식별자(slug)는 <strong>{slug}</strong> 입니다.
      </p>
      <p>여기에 실제 게시물 내용이 표시됩니다.</p>
    </div>
  );
}

실습: 개발 서버가 실행 중인 상태에서 브라우저를 열고 다음 URL로 접속해 보세요.

  • http://localhost:3000/blog/my-first-post
  • http://localhost:3000/blog/nextjs-deep-dive
  • http://localhost:3000/blog/welcome-to-my-blog

각 URL에 따라 페이지 제목과 내용에 slug 값이 다르게 표시되는 것을 확인할 수 있습니다.


다중 동적 라우트 세그먼트

하나의 라우트에 여러 개의 동적 세그먼트를 포함할 수도 있습니다. 예를 들어, 특정 카테고리 내의 블로그 게시물을 나타내는 /blog/[category]/[slug]와 같은 경로를 만들 수 있습니다.

src/app/blog/[category]/[slug]/page.tsx 구조 만들기
page.tsx
...
src/app/blog/[category]/[slug]/page.tsx 파일 내용 작성
src/app/blog/[category]/[slug]/page.tsx
interface CategoryBlogDetailPageProps {
  params: {
    category: string; // [category] 폴더 이름과 일치
    slug: string;     // [slug] 폴더 이름과 일치
  };
}

export default function CategoryBlogDetailPage({ params }: CategoryBlogDetailPageProps) {
  const { category, slug } = params;

  return (
    <div>
      <h1>카테고리: {category}</h1>
      <h2>게시물: {slug}</h2>
      <p>
        이 게시물은 <strong>{category}</strong> 카테고리에 속하며, 식별자는 <strong>{slug}</strong> 입니다.
      </p>
    </div>
  );
}

실습: 이제 다음 URL로 접속해 보세요.

  • http://localhost:3000/blog/web-dev/understanding-react
  • http://localhost:3000/blog/frontend/nextjs-features

URL의 categoryslug 부분이 정확히 추출되어 페이지에 표시되는 것을 볼 수 있습니다.


generateStaticParams 함수

동적 라우트를 가진 페이지를 정적으로 생성(Static Site Generation, SSG)해야 할 때, Next.js는 빌드 시점에 어떤 params 값을 가지고 페이지를 생성할지 알아야 합니다. 이를 위해 generateStaticParams 함수를 사용합니다. 이 함수는 서버 컴포넌트와 동일한 파일에 정의할 수 있습니다.

src/app/blog/[slug]/page.tsx (앞서 만든 파일에 추가)
// ... (BlogDetailPage 컴포넌트 코드) ...

// SSG를 위해 빌드 시 어떤 slug 값을 생성할지 명시
export async function generateStaticParams() {
  const posts = [
    { slug: 'my-first-post' },
    { slug: 'nextjs-deep-dive' },
    { slug: 'understanding-server-components' },
  ];

  // 반환 값은 { slug: '...' } 형태의 객체 배열이어야 합니다.
  return posts;
}

generateStaticParams 함수가 정의되면, Next.js는 빌드 시 이 함수가 반환하는 slug 값들을 사용하여 미리 HTML 페이지를 생성합니다. 이는 첫 로딩 속도를 매우 빠르게 하고, CDN을 통해 콘텐츠를 효율적으로 제공할 수 있게 합니다.

동적 라우트는 Next.js의 강력한 기능 중 하나로, 실제 웹 애플리케이션의 다양한 요구사항을 충족시키는 데 필수적입니다. 이 개념을 잘 이해하고 활용한다면, 유연하고 확장 가능한 웹 서비스를 구축할 수 있을 것입니다.

목차