본문 바로가기

넥스트

[next.js] 5. 동적 라우팅

반응형
 next.js13 공식문서를 번역하여 공부한 내용을 정리한 것이므로 자세한 내용은 공식 사이트를 참고하세요.

 

사전에 정확한 세그먼트 이름을 미리 알 수 없고 동적 데이터에서 라우트를 생성하려는 경우, 요청 시간에 채워지거나 빌드 시간에 사전 렌더링되는 동적 세그먼트를 사용할 수 있습니다.

 

 규칙

동적 세그먼트는 폴더 이름을 대괄호로 묶어서 생성할 수 있습니다 -->  [ 폴더이름 ].

 

예를 들어, [id] 또는 [slug]와 같이 사용할 수 있습니다.



동적 세그먼트는 레이아웃(layout), 페이지(page), 라우트(route), generateMetadata 함수의 params prop으로 전달됩니다.

(개인 정리) 이렇게 생성된 params 는 출력 시 {slug : 경로명} 형태로 나타난다. 예를 들어, /shop/[id] 과 같이 동적 라우팅 경로를 지정하고, 사용자가 http://localhost:3000/shop/5 로 접속하게 되면 params 를 출력 시 {slug : 5} 가 출력된다.

 

 예시

예를 들어, 블로그에서는 다음과 같은 라우트를 포함할 수 있습니다: app / blog / [slug] / page.js 여기서 [slug]는 블로그 포스트의 동적 세그먼트입니다.

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

export default function Page({ params }: { params: { slug: string } }) {
  return <div>내 글: {params.slug}</div>;
}
라우트 예시 URL params
app/blog/[slug]/page.js /blog/a { slug: 'a' } // 사용자가 app/blog/a/page.js 로 접속한 경우
app/blog/[slug]/page.js /blog/b { slug: 'b' }  // 사용자가 app/blog/b/page.js 로 접속한 경우
app/blog/[slug]/page.js /blog/c { slug: 'c' }   // 사용자가 app/blog/c/page.js 로 접속한 경우

 

 정적 params 생성

generateStaticParams 함수동적 라우트 세그먼트와 함께 사용하여 요청 시간이 아닌 빌드 시간에 정적으로 라우트를 생성하는 데 사용할 수 있습니다.

(개인 정리) 요청 시간이 아닌 빌드 시간에 이루어진다는 것은 사용자가 브라우저에 접속 시에 받은 요청으로 라우트를 생성하는 것이 아니라, 클라이언트 요청 이전에 서버 측에서 빌드 시 미리 라우트를 생성한다는 의미이다. 

 

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

export async function generateStaticParams() {
  const posts = await fetch('https://.../posts').then((res) => res.json());

  return posts.map((post) => ({
    slug: post.slug,
  }));
}


generateStaticParams 함수의 주요 이점은 데이터의 스마트한 검색입니다. generateStaticParams 함수 내에서 fetch 요청을 사용하여 콘텐츠를 가져오는 경우, 요청은 자동으로 메모리에 저장됩니다. 이는 여러 generateStaticParams, 레이아웃, 페이지에서 동일한 인수를 사용하는 fetch 요청이 한 번만 이루어지며 빌드 시간이 줄어듭니다.

(개인 정리) 즉, generateStaticParams 함수 내에서 fetch 요청을 사용하면, 해당 요청은 메모리에 저장되고(캐싱된다는 말인듯), 중복된 요청은 배제 시키므로 빌드 시간을 단축 시킨다는 말로 이해된다.

 

더 많은 정보 및 고급 사용 사례에 대해서는 generateStaticParams 서버 함수 문서를 참조하십시오.
https://nextjs.org/docs/app/api-reference/functions/generate-static-params

 

  모든 세그먼트 캐치하기(catch-all)

동적 세그먼트는 대괄호 내부에 ellipsis(...)를 추가하여 후속 세그먼트를 모두 포함할 수 있습니다. 예를 들어, app/shop/[...slug]/page.js는 /shop/clothes뿐만 아니라 /shop/clothes/tops,  /shop/clothes/tops/t-shirts와 같이 모두 일치합니다.

라우트 예시 URL 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'] }

 

(개인 정리) 쉽게 말해, [...slug] 로 전달되는 중첩된 라우팅 경로는 모두 slug 배열에 포함된다

 

 선택적 모든 세그먼트

캐치-all 세그먼트는 이중 대괄호 안에 매개변수를 포함함으로써 선택적으로 만들 수 있습니다. 예를 들어, app/shop/[[...slug]]/page.js는 /shop 뿐만 아니라 /shop/clothes, /shop/clothes/tops, /shop/clothes/tops/t-shirts와 일치합니다.

캐치-all 세그먼트와 선택적 모든 세그먼트의 차이점은 선택적인 경우 매개변수 없이도 라우트가 일치한다는 것입니다 (위의 예제에서 /shop).

라우트 예시 URL 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'] }

 

(개인 정리) 선택적 모든 세그먼트란, 대괄호 안에 두 개의 연속 대괄호([[...]])를 사용하여 만드는 것이다. 이를 통해 해당 세그먼트가 있어도 없어도 되는 경우에 유용하게 사용할 수 있다.

예를 들어, app/shop/[[...slug]]/page.js와 같이 라우트를 만들면, 다음과 같은 URL에 모두 일치한다:

/shop (선택적 세그먼트 없음)
/shop/a (slug: ['a'])
/shop/a/b (slug: ['a', 'b'])
/shop/a/b/c (slug: ['a', 'b', 'c'])

이러한 방식으로 선택적 모든 세그먼트를 사용하면, 세그먼트의 개수가 정해져 있지 않은 경우에 유연하게 대응할 수 있다. 그리고 선택적 모든 세그먼트가 없는 경우에도 해당 라우트에 매칭되므로, 라우트의 다양한 변형을 처리하기에 용이하다.

 

 TypeScript

TypeScript를 사용할 때는 설정된 라우트 세그먼트에 따라 params에 대한 타입을 추가할 수 있습니다.

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

export default function Page({ params }: { params: { slug: string } }) {
  return <h1>내 페이지</h1>;
}

 라우트 params의 타입 정의

app/blog/[slug]/page.js { slug: string }
app/shop/[...slug]/page.js { slug: string[] }
app/[categoryId]/[itemId]/page.js { categoryId: string, itemId: string }

알아두기: 향후 TypeScript 플러그인에서 자동으로 처리될 수 있습니다.

반응형