logo
PostsInvestingHomebarArticlesAbout

Next.js 13 / 06. Dynamic Routes

2023.06.15 / 4min

Intro

정확한 세그먼트 이름을 사전에 알지 못하고 동적인 데이터로 경로를 생성하려는 경우, request를 할 때나 빌드할 때 미리 렌더링되는 동적 세그먼트를 사용할 수 있다.


TOC

Convention

동적 세그먼트는 폴더 이름을 대괄호([]) 로 묶어 만들 수 있습니다: [폴더 이름]. (예: [id] 또는 [slug]).

Group은 소괄호, Dynamic Routes는 대괄호

동적 세그먼트는 layout, page, route, generateMetadata functions에 params로 전달된다.


Example

이 부분은 page 디렉토리 방식과 유사하나, 예시를 보면서 이해하는데 도움이 된다.

app/blog/[slug]/page.tsx
export default function Page({ params }: { params: { slug: string } }) {
  return <div>My Post: {params.slug}</div>
}

위와 같은 경로로 page 파일을 만들었다면 [slug]라고 이름을 지은 폴더명에 따라 Component의 paramsslug라는 이름으로 값이 넘어오게 된다.

RouteExampleURL params
app/blog/[slug]/page.js/blog/a{ slug: 'a' }
app/blog/[slug]/page.js/blog/b{ slug: 'b' }
app/blog/[slug]/page.js/blog/c{ slug: 'c' }

세그먼트에 대한 params를 생성하는 방법을 알아보려면 generateStaticParams() 페이지를 참조하면 된다. Next.js 13으로 블로그를 만들때 유용한 함수다.


Generating Static Params

generateStaticParams 함수는 동적 경로 세그먼트와 함께 사용하여 request시 on-demand가 아닌 빌드 시점에 경로를 정적으로 생성할 수 있다(블로그를 만들때 사용하였다.).

export async function generateStaticParams() {
  const posts = await fetch('https://.../posts').then((res) => res.json())
 
  return posts.map((post) => ({
    slug: post.slug,
  }))
}

generateStaticParams 함수의 가장 큰 장점은 데이터 검색이다. fetch 요청을 사용하여 generateStaticParams 함수 내에서 콘텐츠를 가져오면 요청이 자동 중복제거한다. 즉, 여러 generateStaticParams, Layouts 및 Pages에 걸쳐 동일한 인수를 가진 fetch 요청은 한 번만 수행되므로 빌드 시간이 단축됩니다.


Catch-all Segments

동적 세그먼트는 괄호 안에 줄임표를 추가하여 [...폴더이름] 안에 모든 후속 세그먼트(catch-all subsequent)를 포함하도록 확장할 수 있다.

예를 들어 app/shop/[...slug]/page.js/shop/clothes뿐만 아니라 /shop/clothes/tops, /shop/clothes/tops/t-shirts도 동일한 파일을 사용한다.

RouteExampleURL params
app/shop/[...slug]/page.js/shop/a{ slug: ['a'] }
app/shop/[...slug]/page.js/shop/a/b{ slug: ['a', 'b'] }
app/shop/[...slug]/page.js/shop/a/b/c{ slug: ['a', 'b', 'c'] }

표에서 확인할 수 있듯이 값이 String[]으로 넘어온다는 것을 명심해야한다.


Optional Catch-all Segments

Catch-all Segments는 매개 변수를 이중 대괄호 안에 포함하여 선택 사항으로 만들 수 있다: [[...폴더이름]].

예를 들어, app/shop/[[...slug]]/page.js 파일이 있으면, /shop, /shop/clothes, /shop/clothes/tops, /shop/clothes/tops/t-shirts 모두에서 사용되는 매칭이 되는 것이다.

catch-alloptional catch-all segments의 차이점은 optional인데, 이는 /shop 뒤에 아무런 parameter가 없더라도 optional catch-all segments는 작동한다는 차이점이 있다.

개인적으로는 글만 보고서 차이점이 와닿지 않았다. 그러나 폴더구조로 살펴보면 이해가 잘된다. app/shop/[[...slug]]/page.js이 있고 app/shop/page.js 파일이 없다면 catch-all에서는 Not Found가 나올 것이다. 그러나 optional catch-all에서는 app/shop/[[...slug]]/page.js 파일이 동작해서 나오게 된다.

RouteExampleURL params
app/shop/[[...slug]]/page.js/shop{ }
app/shop/[[...slug]]/page.js/shop/a{ slug: ['a'] }
app/shop/[[...slug]]/page.js/shop/a/b{ slug: ['a', 'b'] }
app/shop/[[...slug]]/page.js/shop/a/b/c{ slug: ['a', 'b', 'c'] }

Reference


avatar
snyungSoftware Engineer(from. 2018)
social-mailsocial-githubsocial-facebooksocial-book