icon안동민 개발노트

동적 라우트 생성


 Next.js의 App Router에서 동적 라우트를 생성하는 것은 유연하고 강력한 웹 애플리케이션을 구축하는 데 핵심적인 부분입니다.

 이 절에서는 동적 세그먼트를 사용하여 동적 라우트를 생성하는 방법과 그 활용에 대해 자세히 알아보겠습니다.

동적 세그먼트 문법

 동적 세그먼트는 대괄호 []를 사용하여 정의됩니다.

 사용 예시

  • [id] : 단일 동적 세그먼트
  • [...slug] : 여러 세그먼트를 포함하는 catch-all 동적 세그먼트
  • [[...slug]] : 선택적 catch-all 동적 세그먼트

기본 동적 라우트 생성

 기본적인 동적 라우트를 생성하는 방법은 다음과 같습니다.

app/blog/[slug]/page.js
export default function BlogPost({ params }) {
  return <h1>Blog Post: {params.slug}</h1>
}

 이 예제에서 [slug]는 동적 세그먼트입니다.

 /blog/my-first-post, /blog/learn-nextjs 등의 URL에 매칭됩니다.

여러 동적 세그먼트 사용

 여러 동적 세그먼트를 조합하여 더 복잡한 라우트를 만들 수 있습니다.

app/products/[category]/[id]/page.js
export default function ProductPage({ params }) {
  return (
    <div>
      <h1>Category: {params.category}</h1>
      <h2>Product ID: {params.id}</h2>
    </div>
  )
}

 이 라우트는 /products/electronics/123과 같은 URL에 매칭됩니다.

Catch-all 세그먼트

 Catch-all 세그먼트를 사용하면 여러 경로 세그먼트를 동적으로 처리할 수 있습니다.

app/docs/[...slug]/page.js
export default function Docs({ params }) {
  return <div>Slug: {params.slug.join('/')}</div>
}

 이 라우트는 /docs/feature/overview, /docs/api/auth/oauth 등 여러 세그먼트를 포함하는 URL에 매칭됩니다.

선택적 Catch-all 세그먼트

 선택적 catch-all 세그먼트를 사용하면 세그먼트가 없는 경우도 처리할 수 있습니다.

app/[[...slug]]/page.js
export default function CatchAllPage({ params }) {
  const slug = params.slug || ['home']
  return <div>Current page: {slug.join('/')}</div>
}

 이 라우트는 /, /about, /products/123 등 모든 URL에 매칭됩니다.

params vs searchParams

 Next.js에서 paramssearchParams는 다른 목적으로 사용됩니다.

 1. params : URL 경로의 동적 세그먼트에서 추출된 값입니다.

  • 예 : /blog/[slug]에서 params.slug로 접근

 2. searchParams : URL의 쿼리 문자열 파라미터입니다.

  • 예 : /search?q=nextjs에서 searchParams.get('q')로 접근

 searchParams 사용 예시

app/search/page.js
export default function SearchPage({ searchParams }) {
  const query = searchParams.q || ''
  return <h1>Search results for: {query}</h1>
}

데이터 페칭과의 연결

 동적 라우트는 6장의 데이터 페칭 부분과 밀접하게 연관됩니다.

 동적 세그먼트의 값을 사용하여 서버에서 필요한 데이터를 가져올 수 있습니다.

 예시

app/products/[id]/page.js
async function getProduct(id) {
  const res = await fetch(`https://api.example.com/products/${id}`)
  return res.json()
}
 
export default async function ProductPage({ params }) {
  const product = await getProduct(params.id)
  return <div>Product: {product.name}</div>
}

 이 예제에서는 동적 세그먼트 [id]의 값을 사용하여 특정 제품의 데이터를 가져옵니다.

실습 : 블로그 포스트 동적 라우트 구현

 다음 요구사항을 만족하는 블로그 포스트의 동적 라우트를 구현해보세요.

  1. /blog/[slug] 형태의 동적 라우트 생성
  2. 블로그 포스트 데이터를 가져오는 비동기 함수 구현 (모의 데이터 사용 가능)
  3. 동적 세그먼트 값을 사용하여 해당 블로그 포스트 데이터 가져오기
  4. 블로그 포스트 제목, 내용, 작성일 표시
  5. 존재하지 않는 포스트에 대한 에러 처리

 구현 단계

  1. app/blog/[slug]/page.js 파일 생성
  2. 비동기 데이터 페칭 함수 구현
  3. 동적 라우트 컴포넌트 구현
  4. 에러 처리 로직 추가

 예시 코드

app/blog/[slug]/page.js
import { notFound } from 'next/navigation'
 
async function getPostData(slug) {
  // 실제 애플리케이션에서는 API나 데이터베이스에서 데이터를 가져옵니다.
  const posts = {
    'first-post': { title: 'First Post', content: 'This is my first post', date: '2023-01-01' },
    'second-post': { title: 'Second Post', content: 'This is my second post', date: '2023-01-02' },
  }
  return posts[slug]
}
 
export default async function BlogPost({ params }) {
  const post = await getPostData(params.slug)
 
  if (!post) {
    notFound()
  }
 
  return (
    <article>
      <h1>{post.title}</h1>
      <p>Published on: {post.date}</p>
      <p>{post.content}</p>
    </article>
  )
}

 이 실습을 통해 동적 라우트의 생성, 데이터 페칭, 그리고 에러 처리를 포함한 실제 시나리오를 경험할 수 있습니다.

 이는 Next.js를 사용하여 동적 콘텐츠를 다루는 웹 애플리케이션을 개발하는 데 필수적인 스킬을 습득하는 데 도움이 될 것입니다.