app/
├── free/
│ ├── page.tsx ← 게시판 목록 (/free)
│ ├── post/
│ │ └── [postId]/
│ │ └── page.tsx ← 게시글 상세 (/free/post/123)
│ └── write/
│ └── page.tsx ← 글쓰기 (/free/write)
├── entertain/
│ ├── page.tsx ← 게시판 목록 (/entertain)
│ ├── post/
│ │ └── [postId]/
│ │ └── page.tsx ← 게시글 상세 (/entertain/post/456)
│ └── write/
│ └── page.tsx ← 글쓰기 (/entertain/write)
├── politics/
│ ├── page.tsx ← 게시판 목록 (/politics)
│ ├── post/
│ │ └── [postId]/
│ │ └── page.tsx ← 게시글 상세 (/politics/post/789)
│ └── write/
│ └── page.tsx ← 글쓰기 (/politics/write)
현재는 고정 게시판별로 free
, entertain
, politics
폴더를 각각 분리해서 관리하고 있었습니다.
게시판 목록, 게시글 상세, 글쓰기 등 구조가 반복되는 형태인데, 최근 수정 페이지를 추가하려다 보니 같은 작업을 여러 폴더에서 반복해야 하는 비효율이 눈에 띄었습니다.
이 구조를 하나로 통합해 중복을 줄이고자 리팩토링을 진행하게 되었습니다.
중복된 게시판 구조를 하나로 통합하기 위해 게시판 이름(board
)을 동적 라우팅 파라미터로 처리하고, 게시글 상세, 글쓰기, 목록 페이지들을 공통 구조로 구성했습니다.
app/
├── [board]/
│ ├── page.tsx ← 게시판 목록 (/free, /entertain, /politics)
│ ├── post/
│ │ ├── [postId]/
│ │ │ └── page.tsx ← 게시글 상세 (/free/post/123)
│ └── write/
│ └── page.tsx ← 글쓰기 (/free/write)
현재 [board]
와 동일한 depth에 home
, hotboard
와 같은 정적 경로가 존재하지만, Next.js에서는 정적 경로가 동적 경로보다 우선순위가 높기 때문에 아래와 같은 폴더 구성이 가능합니다.
[board]
를 동적 라우팅 파라미터로 사용할 경우, 원하는 값인 free
, entertain
, politics
만 허용하도록 제한하는 것이 기본적으로는 불가능합니다.
하지만 [board]/layout.tsx
는 해당 경로로 접근할 때 가장 먼저 실행되는 파일이기 때문에, 이곳에서 동적 라우팅 파라미터 값을 제한하면, 이후의 하위 경로들(post/[postId]
, write
등)에서도 안전하게 일관된 라우팅 처리를 할 수 있습니다.
// [board]/layout.tsx
export default async function Layout({
params,
children,
}: {
params: Promise<{ board: string }>;
children: ReactNode;
}) {
// board가 free, entertain, politics가 아니면 404페이지로 이동
const { board } = await params;
if (board !== 'free' && board !== 'entertain' && board !== 'politics') {
notFound();
}
return <>{children}</>;
}
위와 같이 layout.tsx에서 동적 라우팅 파라미터 값을 제한하면, free
, entertain
, politics
외의 잘못된 URL로 접근할 경우 자동으로 404 페이지로 리다이렉트되며, 하위 라우트(post/[postId]
, write
)에서도 안전하게 렌더링할 수 있습니다.