2025. 1. 20. 07:50ㆍUX Engineer 이야기
들어가며
Intercepting Routes라고 혹시 들어보셨나요?
Next.js 13.3 버전에 추가된 기능이라고 하는데 저는 최근에 알게 되었습니다.
이 기능을 활용하면 모달의 사용성과 사용자 경험을 개선할 수 있을 것 같다는 생각을 하여 공유하고자 합니다.
Intercepting Routes란?
Intercepting Routes는 Next.js에서 도입된 새로운 라우팅 기능입니다. 이 기능을 사용하면 현재 레이아웃 내에서 다른 경로의 콘텐츠를 "가로채서" 표시할 수 있습니다.
사용자가 특정 경로로 이동할 때, 그 경로의 콘텐츠를 현재 페이지 컨텍스트 내에서 표시하는 것입니다. 이는 주로 모달, 슬라이드 오버, 또는 다른 형태의 오버레이 UI 요소를 구현할 때 유용합니다.
작동 방식 및 구현 방법
Intercepting Routes는 특별한 파일 명명 규칙을 사용하여 구현됩니다. 폴더 이름에 (..)를 사용하여 인터셉트할 경로를 지정합니다. 상대 경로 표기법인 ../ 과 유사하지만 세그먼트에 대해 적용됩니다.
- (.) 동일한 수준의 세그먼트와 일치합니다.
- (..) 한 수준 위의 세그먼트와 일치합니다.
- (..)(..) 두 수준 위의 세그먼트와 일치합니다.
- (...) 루트 앱 디렉터리부터의 세그먼트와 일치합니다.
구현 시에는 두 가지 경로를 모두 만들어야 합니다.
- 인터셉트될 실제 경로
- 인터셉팅 경로
이렇게 하면 직접 URL을 입력했을 때는 전체 페이지로 이동하고, 앱 내에서 내비게이션 할 때는 인터셉트된 버전이 표시됩니다.
예시
https://www.instagram.com/pxdstory/
PC에서의 인스타그램입니다.
사진을 선택하면 링크 이동으로 화면이 전환되는 것이 아니라 현재 페이지 컨텍스트가 유지되고 모달로 열고 닫을 수 있습니다.
이 과정에서 모달을 열고 닫을 때 URL이 변경되는 것을 확인할 수 있습니다.
모달이 열린 상태에서 새로고침을 누를 경우 모달 페이지의 상세 페이지로 이동합니다.
UX/UI 개선 포인트
사용자는 현재 페이지의 컨텍스트를 유지하며 새로운 정보를 확인할 수 있습니다.
모달이나 슬라이드 오버 형태로 새로운 콘텐츠를 표시할 수 있어 사용자에게 더 부드럽고 자연스러운 전환 경험을 제공합니다.
그리고 필요한 부분만 업데이트할 수 있어 페이지 로딩 시간을 줄이고 웹사이트의 응답성을 향상시킵니다.
브라우저의 히스토리 API와 잘 통합됩니다. 사용자는 브라우저의 뒤로 가기 버튼을 사용하여 이전 상태로 쉽게 돌아갈 수 있습니다.
전통적인 모달은 주로 JavaScript로 구현되어 URL과 무관했습니다.
Intercepting Routes를 사용하면 모달의 내용을 URL과 연결할 수 있어, 다음과 같은 이점이 있습니다:
- 일관성: 모달의 내용이 고유한 URL을 갖게 되어 디자인의 일관성을 유지하기 쉬워집니다.
- 공유 가능성: 모달의 내용을 직접 공유할 수 있어 사용자 경험이 향상됩니다.
- SEO 친화적: 모달 내용도 개별 페이지로 존재하므로 검색 엔진 최적화에 도움이 됩니다.
더 이상 모달과 URL을 연결하려고 모달의 상태를 URL에 저장하지 않아도 됩니다.
실제 구현
Intercepting Routes를 구현하는 기본적인 방법을 살펴보겠습니다.
app 폴더에 이미지와 같이 구성하였고, 주요 코드는 아래와 같습니다.
전체 코드 레포지토리 : https://github.com/doworld-dev/intercepting-routes
// app/photos/page.tsx
<ul className={styles.photoList}>
{photos.map(({ id, imageSrc }) => (
<li key={id} className={styles.photoItem}>
<Link href={`/photos/${id}`} className={styles.photoLink}>
<Image
src={imageSrc}
width={300}
height={300}
alt={`Photo ${id}`}
/>
</Link>
</li>
))}
</ul>
// app/photos/layout.tsx
const PhotosLayout = ({ children, modal }: PhotosLayoutProps) => {
return (
<>
{children}
{modal}
</>
);
};
// app/photos/@modal/(..)photos/[id]/page.tsx
const PhotoModal = ({ params: { id } }: PhotoModalProps) => {
const photo: Photo = photos.find((p) => p.id.toString() === id)!;
return (
<Modal>
<PhotoCard photo={photo} />
</Modal>
);
};
// app/photos/[id]/page.tsx
const PhotoPage = ({ params: { id } }: PhotoPageProps) => {
const photo: Photo = photos.find((p) => p.id.toString() === id)!;
return (
<div>
<Link href="/photos">Back</Link>
<PhotoCard photo={photo} />
<p>상세 페이지</p>
</div>
);
};
<Link href={`photos/${id}`}>를 통해 링크를 눌렀을 때 /(..)photos/[id] 경로에 있는 페이지가 인터셉트 되면서 모달로 보여줍니다.
새로고침을 하거나 /photo/1 과 같이 직접 URL로 접근을 할 경우 /photo/[id] 의 페이지가 로드됩니다.
예제에서 Intercepting Routes와 함께 Parallel Routes라는 것을 함께 사용해 보았습니다.
슬롯을 통해 동일한 라우트에서 여러 페이지를 동시에 또는 조건부로 렌더링 할 수 있는 기능입니다.
app 디렉터리 하위에 작성된 코드에서만 사용할 수 있습니다.
@folder를 선언해서 만들 수 있고 공유된 부모 레이아웃에 props로 전달됩니다.
* app/photos/layout.tsx의 modal 부분과 app/photos/@modal 폴더 참고
마치며
Intercepting Routes의 기능을 통해 우리는 원활한 페이지 전환으로 더 부드러운 사용자 경험을 제공할 수 있고, 복잡한 UI 패턴을 보다 수월하게 구현할 수 있습니다. 빠른 로딩과 응답성, SEO에 친화적인 부분도 도움이 되고요.
https://intercepting-routes-next.vercel.app/photos 주소로 접속하시면 예시로 보여드린 인스타그램과 동일한 방식으로 동작하는 것을 확인하실 수 있습니다.
이것으로 intercepting routes 기능의 소개를 마치겠습니다.
감사합니다.
이 글은 pxd XE Group Blog에서도 보실 수 있습니다.