기억보단 기록을/Next JS (App Router)

[NextJS 13] Routing - Dynamic Routes

_OIL 2023. 6. 6. 00:04
반응형

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

Convention

동적 세그먼트는 폴더 이름을 대괄호로 묶음으로써 생성할 수 있습니다: [folderName]. 예를 들어 [id] 또는 [slug]입니다. 동적 세그먼트는 레이아웃, 페이지, 경로 및 generateMetadata 함수에 params 소품으로 전달됩니다.

Example

예를 들어 블로그에는 app/blog/[slug]/page.js 경로가 포함될 수 있습니다. 여기서 [slug]는 블로그 게시물의 동적 세그먼트입니다.

/* app/blog/[slug]/page.js */

export default function Page({ params }) {
  return <div>My Post</div>;
}

Route Example URL 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' }

동적 세그먼트는 페이지 디렉토리의 동적 경로와 동일합니다.

Generating Static Params

generateStaticParams 함수는 동적 라우트 세그먼트와 결합하여 라우트를 빌드 시간에 정적으로 생성하는 데 사용될 수 있습니다.

/* app/blog/[slug]/page.tsx */
import React from "react";

interface Post {
  createdAt: string;
  name: string;
  avatar: string;
  slug: string;
}

interface PageProps {
 params: { slug: Post["slug"] };
}

export async function generateStaticParams() {
  const posts: Post[] = await fetch(`${process.env.MOCK_API_URL}/posts`).then(
    (res) => res.json()
  );

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

const Page = ({ params }: PageProps) => {
  return <div>{JSON.stringify(params)}</div>;
};

export default Page;

위 코드를 가진 프로젝트를 yarn build 하면 아래 그림 처럼 ${process.env.MOCK_API_URL}/posts 의 데이터를 미리 호출한 정적 페이지가 생성된것 을 볼 수 있습니다.

또한 generateStaticParams 함수의 주요 이점은 데이터를 스마트하게 관리 하다는 것 입니다. generateStaticParams 함수 내에서 fetch 요청을 사용하여 동일한 콘텐츠를 가져오는 경우 자동으로 중복 제거됩니다. 이는 여러 generateStaticParams, 레이아웃 및 페이지에서 동일한 인수를 가진 fetch 요청이 한 번만 실행되므로 빌드 시간을 단축합니다.

Catch-all Segments

[...folderName] 괄호 안에 줄임표를 추가하여 동적 세그먼트를 모든 후속 세그먼트로 확장할 수 있습니다.

예를 들어 app/shop/[...slug]/page.js는 /shop/clothes와 일치하지만 /shop/clothes/tops, /shop/clothes/tops/t-shirts 등과도 일치합니다.

Route Example 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'] }

Optional Catch-all Segments

포괄적인 세그먼트는 [[...folderName]]과 같이 이중 대괄호 안에 매개 변수를 포함하여 옵션으로 만들 수 있습니다.

예를 들어 app/shop/[[...slug]]/page.js는 /shop/clothes, /shop/clothes/tops, /shop/clothes/tops/t-shirts 외에도 /shop과도 일치합니다.

Route Example 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'] }

Typescript

TypeScript를 사용할 때 구성된 라우트 세그먼트에 따라 매개변수 유형을 추가할 수 있습니다.

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

Playground

느낀점

동적 라우트라도 generateStaticParams함수를 사용하면 빌드 시 정적파일로 미리 생성할 수 있어서 고급화된 사용자 접근 시나리오를 구현 할 수 있어보입니다. 예를 들어 인기글이나 사용자 접근이 많은 상세페이지 30개 정도만 미리 정적 페이지를 만들어 두면 사용자 경험이 좋아질 것 입니다.

참조

 

Routing: Dynamic Routes | Next.js

Using App Router Features available in /app

nextjs.org

반응형