동적 라우트 생성
이전 장에서 우리는 정적인 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
폴더를 생성합니다. (만약 없다면)src/ └── app/ ├── blog/ <- 여기에 blog 폴더 생성 ├── ...
-
[slug]
폴더 생성:src/app/blog
안에[slug]
라는 이름의 폴더를 생성합니다. 여기서slug
는 동적인 값이 들어갈 파라미터의 이름이 됩니다.src/ └── app/ ├── blog/ │ └── [slug]/ <- 여기에 [slug] 폴더 생성 ├── ...
-
page.tsx
파일 생성:src/app/blog/[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
구조 만들기src/ └── app/ └── blog/ └── [category]/ <- [category] 폴더 └── [slug]/ <- [slug] 폴더 └── page.tsx <- 페이지 파일
-
src/app/blog/[category]/[slug]/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의 category
와 slug
부분이 정확히 추출되어 페이지에 표시되는 것을 볼 수 있습니다.
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의 강력한 기능 중 하나로, 실제 웹 애플리케이션의 다양한 요구사항을 충족시키는 데 필수적입니다. 이 개념을 잘 이해하고 활용한다면, 유연하고 확장 가능한 웹 서비스를 구축할 수 있을 것입니다.