Next.js의 Catch-all 라우팅은 동적 라우팅의 한 형태로, 특정 경로 아래의 모든 하위 경로를 하나의 페이지에서 처리할 수 있게 해주는 기능입니다. 이는 다양한 깊이의 경로를 가진 콘텐츠를 관리하거나, 사용자 정의 경로를 처리해야 할 때 유용합니다.
대괄호([]) 안에 점 세 개(...)를 사용하여 Catch-all 세그먼트를 정의합니다.
예를 들어, [...slug].js 또는 [...path].js와 같은 파일 이름을 사용합니다.
정의된 세그먼트 아래의 모든 하위 경로를 매칭합니다.
매칭된 경로는 배열 형태로 페이지 컴포넌트의 params prop으로 전달됩니다.
다양한 깊이의 경로를 가진 콘텐츠를 하나의 페이지에서 처리할 수 있습니다.
사용자 정의 경로, 블로그 카테고리, 문서 시스템 등에 유용합니다.
/blog/category/article
/blog/2024/01/01/my-article
/blog/any/number/of/segments
'use client';
export default function BlogCatchAll({ params }) {
const { slug } = params;
return (
<div>
<h1>Blog Catch-all</h1>
<p>Slug: {slug.join('/')}</p>
</div>
);
}
위 코드에서 /blog/category/article 경로로 접속하면 params.slug는 ['category', 'article'] 배열이 됩니다.
/blog/2024/01/01/my-article 경로로 접속하면 params.slug는 ['2024', '01', '01', 'my-article'] 배열이 됩니다.
Catch-all 라우팅은 모든 하위 경로를 매칭하므로, 특정 경로를 제외해야 하는 경우 조건부 로직을 추가해야 합니다.
과도한 Catch-all 라우팅 사용은 URL 구조를 복잡하게 만들 수 있으므로, 적절한 수준에서 사용하는 것이 좋습니다.
http://localhost:3000/archive/2024/3 의 예시로 접근해서 해당하는 URL의 연도와 월에 해당하는 news 기사를 가져 오는 로직
export default function FilteredNewsPage({params}) {
const filter = params.filter;
const selectedYear = filter?.[0];
const selectedMonth = filter?.[1];
let news;
let links = getAvailableNewsYears();
// 년도만 존재 할 때 ..
if (selectedYear && !selectedMonth) {
news = getNewsForYear(selectedYear);
// 년도에 해당하는 월 뽑아오기
links = getAvailableNewsMonths(selectedYear);
}
// 둘다 존재 할 때..
if (selectedYear && selectedMonth) {
news = getNewsForYearAndMonth(selectedYear, selectedMonth);
// 링크 비워주기
links = [];
}
let newsContent = <p>No news found for the selected period.</p>
if (news && news.length > 0) {
newsContent = <NewsList news={news} />
}
// 지정하지 않은 path 및 slug가 들어올 때
if (
selectedYear &&
!getAvailableNewsYears().includes(+selectedYear) ||
selectedMonth &&
!getAvailableNewsMonths(selectedYear).includes(+selectedMonth)
) {
throw new Error('Invalid Error');
}
return (
<>
<header id="archive-header">
<nav>
<ul>
{links.map((link) => {
const href = selectedYear
? `/archive/${selectedYear}/${link}`
: `/archive/${link}`;
return (
<li key={link}>
<Link href={href}>{link}</Link>
</li>
);
})}
</ul>
</nav>
</header>
{newsContent}
</>
);
}