| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 | 12 | 13 | 14 |
| 15 | 16 | 17 | 18 | 19 | 20 | 21 |
| 22 | 23 | 24 | 25 | 26 | 27 | 28 |
- 차이점
- git flow start
- Main
- js
- 다시 홧팅
- 클라이언트 컴포넌트
- AJAX
- jQuery
- api 라우트
- Mac
- 서버 컴포넌트
- 실무는 공식문서로
- git
- 개발일지
- CSS
- JavaScript
- axios
- 책으론 원리만
- freecodecamp
- TS
- 백준
- git flow finish
- 힘들었던 한주
- 끝까지 잘 마무리하기
- Next.js
- javascript30
- 공부할 거 넘많다~
- HTML
- fetch pull 차이
- 바닐라JS
- Today
- Total
다다의 개발일지 6v6
[Next.js] App Router - 디렉토리 기반의 라우팅! 신기하다.. 본문
앱 라우팅(App Router)
Next.js 13부터 디렉토리 기반의 라우팅 App Router가 도입됐다고 한다.
기존의 pages/ 방식과 다르게, 파일과 폴더 구조만으로 자동으로 라우팅이 설정된다
기본 구조
Next.js에서 app/ 폴더 안에 파일을 추가하는 것만으로 페이지를 생성할 수 있음
📂 디렉토리 구조 예시
/app
├─ layout.tsx # 모든 페이지에 공통 적용 (레이아웃)
├─ page.tsx # `/` (홈 페이지)
├─ about/
│ ├─ page.tsx # `/about` 페이지
├─ blog/
│ ├─ page.tsx # `/blog` 페이지
│ ├─ post/
│ │ ├─ page.tsx # `/blog/post` 페이지
- page.tsx → 해당 경로의 메인 페이지
- layout.tsx → 해당 폴더 내 모든 페이지에 공통 적용되는 레이아웃
동적 라우팅 (Dynamic Routing)
폴더 이름을 [param] 형태로 만들면, 동적인 경로를 처리할 수 있다
예제: 동적인 블로그 포스트 페이지
/app
├─ blog/
│ ├─ [id]/
│ │ ├─ page.tsx # `/blog/:id` 형태의 동적 페이지
/blog/hello-world 요청 시 id 값 가져오기
// app/blog/[id]/page.tsx
import { useParams } from "next/navigation";
export default function BlogPost() {
const params = useParams(); // { id: "hello-world" }
return <h1>Blog Post: {params.id}</h1>;
}
- /blog/hello-world → params.id = "hello-world"
- /blog/my-first-post → params.id = "my-first-post"
병렬 라우팅 (Parallel Routes)
Next.js에서는 여러 레이아웃을 동시에 렌더링할 수도 있다
예제: 대시보드의 사이드바 & 콘텐츠 분리
/app
├─ layout.tsx
├─ dashboard/
│ ├─ layout.tsx # 대시보드 전체 레이아웃
│ ├─ page.tsx # `/dashboard` 메인 페이지
│ ├─ sidebar.tsx # 사이드바
layout.tsx에서 병렬 렌더링 적용
// app/dashboard/layout.tsx
export default function DashboardLayout({ children, sidebar }: { children: React.ReactNode, sidebar: React.ReactNode }) {
return (
<div style={{ display: "flex" }}>
<aside>{sidebar}</aside>
<main>{children}</main>
</div>
);
}
인터셉트 라우팅 (Intercepting Routes)
- 기존 페이지를 변경하지 않고, 특정 조건에서 기존 페이지 대신 새로운 UI를 띄우는 기능
- 예를 들어, 모달을 띄우고 싶을 때 사용 가능!
- /profile을 직접 방문하면 원래 페이지가 뜨고, 특정 상황에서만 모달을 띄움.
- 어떤 페이지에서 이동하느냐에 따라 다르게 렌더링되게 만드는 기능
예제: /profile 대신 모달 띄우기
/app
├─ profile/
│ ├─ page.tsx # 기본 `/profile` 페이지
├─ (modal)/
│ ├─ profile/
│ │ ├─ page.tsx # `/profile`를 모달로 인터셉트
// app/(modal)/profile/page.tsx
export default function ProfileModal() {
return <div className="modal">✨ 모달 프로필 화면 ✨</div>;
}
적용하는 방법 (링크 설정)
Next.js에서 <Link>를 사용할 때, as 속성을 이용하면 인터셉트 라우팅을 적용할 수 있다
import Link from "next/link";
export default function Dashboard() {
return (
<div>
<h1>대시보드</h1>
{/* `as` 속성을 추가하면 인터셉트 라우팅 적용됨 */}
<Link href="/profile" as="/dashboard?modal=profile">
프로필 보기 (모달)
</Link>
</div>
);
}
- 모달을 띄울 때 → /dashboard?modal=profile
- 일반 방문 → /profile 그대로 실행
App Router에서 모달을 띄우는 방법 (3가지)
as는 단순히 URL을 다르게 보이게 하기 위한 선택적인 기능이고, 모달을 띄우는 방법 자체는 여러 가지가 있다!
- as 속성을 활용한 인터셉트 라우팅 → useParams()로 상태 변경
- URL 상태 기반 모달 (useSearchParams()) → ?modal=true 같은 쿼리 파라미터 사용
- 전역 상태 관리 (Recoil, Zustand 등) → URL과 관계없이 모달 상태 관리
1️⃣ as 속성을 활용한 인터셉트 라우팅
인터셉트 라우팅을 활용하면, /profile을 직접 입력하면 기본 페이지가 뜨고, 특정 상황에서만 모달이 뜨도록 할 수 있다
📂 디렉토리 구조
/app
├─ profile/
│ ├─ page.tsx # 기본 `/profile` 페이지
├─ (modal)/profile/
│ ├─ page.tsx # `/profile`을 인터셉트해서 모달로 띄우는 페이지
✅ 대시보드에서 프로필을 모달로 띄우기
import Link from "next/link";
export default function Dashboard() {
return (
<div>
<h1>대시보드</h1>
{/* `as` 속성을 추가하면 인터셉트 라우팅 적용됨 */}
<Link href="/profile" as="/dashboard?modal=profile">
프로필 보기 (모달)
</Link>
</div>
);
}
- /profile을 직접 방문하면 app/profile/page.tsx가 실행됨
- /dashboard?modal=profile로 이동하면 app/(modal)/profile/page.tsx가 실행되면서 모달이 뜸
2️⃣ useSearchParams()로 URL 상태 기반 모달 띄우기
인터셉트 라우팅 없이도 useSearchParams()를 활용해서 쿼리 파라미터를 감지하면 모달을 띄울 수 있다!
✅ 대시보드에서 쿼리 기반으로 모달 띄우기
"use client";
import { useSearchParams, useRouter } from "next/navigation";
export default function Dashboard() {
const searchParams = useSearchParams();
const router = useRouter();
const isModalOpen = searchParams.get("modal") === "profile";
return (
<div>
<h1>대시보드</h1>
{/* 클릭하면 ?modal=profile 추가됨 */}
<button onClick={() => router.push("?modal=profile")}>
프로필 보기 (모달)
</button>
{/* 모달이 열릴 때만 표시 */}
{isModalOpen && (
<div className="modal">
<h2>프로필 모달</h2>
<button onClick={() => router.push("/")}>닫기</button>
</div>
)}
</div>
);
}
- ?modal=profile이 URL에 추가되면 모달이 열림
- 닫기 버튼을 누르면 router.push("/")로 변경되면서 모달 닫힘
→ URL이 상태 관리 역할을 하도록 하는 방법
3️⃣ 전역 상태 관리 라이브러리 활용 (Recoil, Zustand 등)
Next.js의 앱 라우팅을 이용하지 않고도 상태 관리 라이브러리(Recoil, Zustand)를 활용해서 모달을 띄울 수도 있음
// store/modalStore.ts
import { create } from "zustand";
type ModalStore = {
isOpen: boolean;
openModal: () => void;
closeModal: () => void;
};
export const useModalStore = create<ModalStore>((set) => ({
isOpen: false,
openModal: () => set({ isOpen: true }),
closeModal: () => set({ isOpen: false }),
}));
"use client";
import { useModalStore } from "@/store/modalStore";
export default function Dashboard() {
const { isOpen, openModal, closeModal } = useModalStore();
return (
<div>
<h1>대시보드</h1>
<button onClick={openModal}>프로필 보기 (모달)</button>
{isOpen && (
<div className="modal">
<h2>프로필 모달</h2>
<button onClick={closeModal}>닫기</button>
</div>
)}
</div>
);
}
- openModal() 호출하면 isOpen이 true로 변경되면서 모달 열림
- closeModal() 호출하면 isOpen이 false가 되어 모달 닫힘
→ URL과 무관하게 모달을 띄울 수 있는 방법
어떤 방법을 써야 할까?
| as를 활용한 인터셉트 라우팅 | 페이지 이동 기반, 자동으로 상태 관리 | Next.js 라우팅을 이해해야 함 | SSR & SEO가 중요한 경우 |
| useSearchParams() 활용 | 간단하게 URL 상태 관리 가능 | URL이 바뀌는 게 싫을 수도 있음 | 클라이언트 사이드에서 모달 띄울 때 |
| Zustand 같은 전역 상태 관리 | URL 영향 없이 자유롭게 모달 띄울 수 있음 | 새로고침하면 상태 초기화됨 | URL과 관계없이 모달이 필요할 때 |
404 페이지 (Not Found)
Next.js에서는 자동으로 not-found.tsx를 만들면 404 페이지를 처리할 수 있음. 굿
// app/not-found.tsx
export default function NotFound() {
return <h1>😢 페이지를 찾을 수 없습니다.</h1>;
}
이제 존재하지 않는 페이지로 가면 자동으로 이 컴포넌트가 표시됨
정리 (Next.js 앱 라우팅 핵심 개념)
| 파일 기반 라우팅 | app/ 폴더에 page.tsx 추가하면 자동으로 페이지 생성 |
| 동적 라우팅 | [id] 폴더로 동적 경로 가능 (/blog/:id) |
| 병렬 라우팅 | 여러 개의 레이아웃을 병렬로 렌더링 가능 |
| 인터셉트 라우팅 | 기존 페이지를 가리지 않고 특정 조건에서 다른 UI 표시 가능 (ex. 모달) |
| 404 페이지 | not-found.tsx 파일로 404 처리 가능 |
'Frontend > Next.js' 카테고리의 다른 글
| [Next.js] 모던 리액트 Deep Dive _ next.js 톺아보기 ( 공식문서로 공부하자.. ㅎ ) (0) | 2025.03.22 |
|---|---|
| [Next.js] 서버 vs 클라이언트 컴포넌트에서 - fetch, axios로 API 호출 차이점 (4) | 2025.03.15 |
| [Next.js] 백엔드 설정하기, 서버 vs 클라이언트 컴포넌트 차이점 (0) | 2025.03.09 |
| [Next.js] Next.js에서 <a> 대신 <Link>를 사용하는 이유 ?! - SPA를 위해 (0) | 2025.03.01 |
| [Next.js] - react 기반의 풀스택 프레임워크!! 배워봅시당 (2) | 2025.03.01 |