본문 바로가기
웹 프로그래밍/Next.js

[Next.js 공식문서 정리] Routing : 09. Intercepting Routes

by 청량리 물냉면 2025. 3. 29.
반응형

9. 경로 가로채기(Intercepting Routes)

✅ Intercepting Routes란?

Intercepting Routes는 Next.js에서 특정 경로를 가로채서 현재 페이지 위에 새로운 UI(예: 모달, 슬라이드 패널 등)를 표시하는 기능이다.

➡️ 즉, 새로운 페이지로 완전히 이동하지 않고, 현재 페이지 위에 겹쳐서 특정 UI를 보여줄 수 있도록 해준다.

✅ 왜 필요한가?

보통 모달을 구현할 때 사용된다.
예를 들어, 사용자가 /products 페이지에서 상품 목록을 보고 있다가, 특정 상품을 클릭하면 상품 상세 페이지를 모달로 표시하고 싶을 때 유용하다.

기존 방식

  • 상품 목록 /products → 상품 상세 /products/1 로 이동하면 페이지가 새로고침됨

Intercepting Routes 사용 시

  • /products 위에 /products/1을 모달로 겹쳐서 표시할 수 있음
  • 뒤로 가기 버튼을 누르면 모달만 닫히고 /products 페이지는 그대로 유지됨

✅ 규칙(Convention)

경로 가로채기는 (..) 규칙을 사용하여 정의할 수 있으며, 이는 파일 시스템의 상대 경로(../)와 유사하지만, 라우트 세그먼트(segment) 단위로 동작한다.
사용할 수 있는 규칙은 다음과 같다.

  • (.) → 같은 수준의 세그먼트를 일치시킴
  • (..) → 한 단계 위의 세그먼트를 일치시킴
  • (..)(..) → 두 단계 위의 세그먼트를 일치시킴
  • (...) → 애플리케이션의 루트(app 디렉토리)부터 세그먼트를 일치시킴

풀어서 이해하기

여기서 "일치시킨다(match)" 는 말은 특정 경로(라우트)가 기존 경로 대신 특정 경로를 가로채서(인터셉트해서) 렌더링된다는 의미이다.

(..) 규칙은 파일 시스템에서 ../로 한 단계 위의 디렉토리로 이동하는 것과 비슷한 방식으로 경로를 가로채는 기능을 한다. 다만, 여기서는 디렉토리 대신 Next.js의 라우트 세그먼트(segment) 단위로 동작한다.

예제 📝

📂 디렉토리 구조

  • /photo 경로로 접근하면 기본적으로 app/photo/page.tsx가 렌더링됨
  • 하지만 /feed 내부에서 /photo 경로로 이동하면, app/photo/page.tsx 대신 app/feed/(..)photo/page.tsx가 렌더링됨
    → 즉, 기존 /photo 경로를 가로채서(Intercept), feed/(..)photo/page.tsx의 내용을 보여줌

📌 (..) 규칙 정리

규칙 설명
(.) 현재 경로(같은 세그먼트)에서 가로채기
(..) 한 단계 위 세그먼트에서 가로채기
(..)(..) 두 단계 위 세그먼트에서 가로채기
(...) 애플리케이션 루트부터 가로채기

쉽게 말해, (..)를 사용하면 특정 경로의 내용을 기존 페이지가 아니라 다른 페이지로 바꿀 수 있다는 뜻!

✅ Intercepting Routes 사용 예제 (모달)

1️⃣ 기본 설정

📁 폴더 구조

/app
├── layout.tsx
├── page.tsx # 기본 페이지
├── products
│ ├── page.tsx # 상품 목록 페이지 (/products)
│ ├── [id]
│ │ ├── page.tsx # 상품 상세 페이지 (/products/1)
│ │ ├── @modal
│ │ │ ├── page.tsx # 상품 상세 모달 (/products/1 - 모달)

2️⃣ 상품 목록 페이지 (/products)

// app/products/page.tsx
"use client";
import Link from "next/link";
export default function Products() {
const products = [
{ id: 1, name: "상품 A" },
{ id: 2, name: "상품 B" },
];
return (
<div>
<h1>상품 목록</h1>
{products.map((product) => (
<Link key={product.id} href={`/products/${product.id}`} as={`/products/${product.id}`} scroll={false}>
<div className="border p-2 cursor-pointer">
{product.name}
</div>
</Link>
))}
</div>
);
}

✔️ scroll={false}: 모달을 열 때 페이지 스크롤 위치 유지

3️⃣ 상품 상세 페이지 (/products/1)

// app/products/[id]/page.tsx
export default function ProductDetail({ params }: { params: { id: string } }) {
return (
<div>
<h1>상품 상세 페이지</h1>
<p>상품 ID: {params.id}</p>
</div>
);
}

✔️ /products/1에 들어가면 일반적인 페이지 이동이 발생

4️⃣ 모달을 위한 Intercepting Route (/products/1을 모달로 표시)

// app/products/[id]/@modal/page.tsx
"use client";
import { useRouter } from "next/navigation";
export default function ProductModal({ params }: { params: { id: string } }) {
const router = useRouter();
return (
<div className="fixed inset-0 bg-black/50 flex justify-center items-center">
<div className="bg-white p-4 rounded shadow-lg">
<h1>상품 상세 모달</h1>
<p>상품 ID: {params.id}</p>
<button onClick={() => router.back()} className="mt-2 bg-gray-200 p-2">
닫기
</button>
</div>
</div>
);
}

✔️ router.back()을 사용하면 뒤로 가기 버튼을 눌렀을 때 모달만 닫히고 /products 페이지는 그대로 유지됨
✔️ @modal을 사용하면 현재 페이지 위에 모달 형태로 겹쳐서 표시 가능

✅ Intercepting Routes 정리

  • 일반적인 페이지 이동 없이 특정 UI(모달 등)를 현재 페이지 위에 겹쳐서 표시할 수 있음.
  • 뒤로 가기(History API)를 사용하여 모달만 닫고 현재 페이지를 유지할 수 있음
  • 페이지 전체를 다시 로드하지 않고 부드러운 UX를 제공 가능

추가 : Intercepting Routes의 Soft Navigation vs. Hard Navigation

🔹 Soft Navigation (부드러운 네비게이션)

✔️ 현재 페이지(백그라운드)를 유지하면서 새로운 UI를 오버레이
✔️ 페이지 전체가 새로고침되지 않고, 상태(state)가 유지됨
✔️ Next.js에서 Intercepting Routes를 활용하면 모달 같은 UI를 Soft Navigation으로 구현 가능
✔️ URL이 변경되지만, 기존 페이지 콘텐츠는 그대로 남아 있음

📌 예제: 모달을 Soft Navigation으로 띄우기

// app/feed/`(..)`photo/page.tsx
"use client";
import { useRouter } from "next/navigation";
export default function PhotoModal() {
const router = useRouter();
return (
<div className="fixed inset-0 bg-black/50 flex justify-center items-center">
<div className="bg-white p-4 rounded">
<h1>사진 상세 모달</h1>
<button onClick={() => router.back()}>닫기</button>
</div>
</div>
);
}

/feed/photo 방문 시 모달이 뜨고, 기존 feed 페이지는 그대로 있음
✅ 뒤로 가기(router.back()) 시 모달만 닫힘, 기존 feed 페이지 유지됨

🔹 Hard Navigation (완전한 네비게이션)

✔️ 기존 UI를 제거하고 새 페이지로 완전히 이동
✔️ 브라우저가 전체 페이지를 다시 로드할 수도 있음
✔️ 페이지 전환 시 상태(state)가 초기화됨
✔️ 백그라운드 UI 없음, 브라우저 새로고침과 비슷
✔️ 일반적인 페이지 전환 방식과 동일

📌 예제: Hard Navigation

// 특정 버튼 클릭 시 Hard Navigation 실행
"use client";
import { useRouter } from "next/navigation";
export default function GoToPhotoPage() {
const router = useRouter();
return (
<button onClick={() => router.push("/feed/photo")}>
사진 페이지로 이동
</button>
);
}

/feed/photo 이동 시 기존 feed 페이지가 사라지고 완전히 새로운 페이지로 로드됨
✅ 새로고침한 것처럼 동작하여 기존 상태(state)가 사라질 수 있음

🔹 Soft vs. Hard 네비게이션 차이 정리

  Soft Navigation Hard Navigation
기존 페이지 유지 유지됨 제거됨
백그라운드 UI 있음 (예: 모달) 없음
네비게이션 속도 빠름 (클라이언트 사이드) 느림 (완전한 페이지 로드)
사용 예시 모달, 사이드바 일반적인 페이지 전환

✅ 정리

  • Soft Navigation → 기존 페이지 유지하면서 새로운 UI 추가 (모달, 사이드바)
  • Hard Navigation → 기존 페이지를 제거하고 완전히 새로운 페이지로 이동
    Intercepting Routes 활용하면 Soft Navigation으로 부드러운 UX 구현 가능

 

 


https://nextjs.org/docs/app/building-your-application/routing/intercepting-routes

 

Routing: Intercepting Routes | Next.js

Use intercepting routes to load a new route within the current layout while masking the browser URL, useful for advanced routing patterns such as modals.

nextjs.org

 

반응형