동적 라우트 생성
이전 장에서는 정적인 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 파일을 생성합니다.
src/app/blog/[slug]/page.tsx 파일 내용 작성:
이 page.tsx 컴포넌트는 params라는 prop을 통해 URL에서 추출된 동적인 값을 전달받습니다.
// 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-posthttp://localhost:3000/blog/nextjs-deep-divehttp://localhost:3000/blog/welcome-to-my-blog
각 URL에 따라 페이지 제목과 내용에 slug 값이 다르게 표시되는 것을 확인할 수 있습니다.
다중 동적 라우트 세그먼트
하나의 라우트에 여러 개의 동적 세그먼트를 포함할 수도 있습니다. 예를 들어, 특정 카테고리 내의 블로그 게시물을 나타내는 /blog/[category]/[slug]와 같은 경로를 만들 수 있습니다.
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-reacthttp://localhost:3000/blog/frontend/nextjs-features
URL의 category와 slug 부분이 정확히 추출되어 페이지에 표시되는 것을 볼 수 있습니다.
generateStaticParams 함수
동적 라우트를 가진 페이지를 정적으로 생성(Static Site Generation, SSG)해야 할 때, Next.js는 빌드 시점에 어떤 params 값을 가지고 페이지를 생성할지 알아야 합니다. 이를 위해 generateStaticParams 함수를 사용합니다. 이 함수는 서버 컴포넌트와 동일한 파일에 정의할 수 있습니다.
// ... (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의 강력한 기능 중 하나로, 실제 웹 애플리케이션의 다양한 요구사항을 충족시키는 데 필수적입니다. 이 개념을 잘 이해하고 활용한다면, 유연하고 확장 가능한 웹 서비스를 구축할 수 있을 것입니다.