[Next.js]Routing - Parallel Routes로 모달 관리

Yeong·2025년 10월 16일

기존의 모달 구현 방식은 useState를 활용하여 작업했었다.

const [isModalOpen, setIsModalOpen] = useState(false);
// 모달 열기
const openModal = () => setIsModalOpen(true);
// 모달 닫기
const closeModal = () => setIsModalOpen(false);

// 또는 const toggleModal = () => setIsModalOpen(prev => !prev); 

그러나 해당 방식은 새로고침 시 모달이 사라지고 모달이 열린 상태의 URL을 공유할 수 없다.

Parallel Routes는 이러한 문제를 해결하여 이름그대로 병렬적인 라우트를 만들 수 있다.
모달을 위한 별도의 라우트를 만들어서 메인 페이지와 병렬적으로(Parallel) 관리할 수 있다.

예를들어, 특정 페이지에서 사용자가 버튼을 누르면 상품리스트 모달이 뜨고 상품 클릭 시 상세화면으로 이동한다면 폴더 구조는 아래와 같다.

app/
..list/
....page.tsx
....layout.tsx
....@modal/
.......default.tsx
.......products-modal/page.tsx

쿼리스트링 모달의 장점은 모달상태제어를 쿼리스트링으로 할 수 있으며, default.tsx 에서 여러 모달을 분기처리 할 수 있다는 점이다.

기본적으로 부모 layout에 {modal}을 두어야한다. 그 뒤는 아래의 과정 !

1. @modal 슬롯 생성하여 사용할 모달 생성

// default.tsx 

"use client";
import { useSearchParams } from "next/navigation";
import ProductsModal from "@/app/list/@modal/products-modal/page";

const MODAL_COMPONENTS: Record<string, React.ReactNode> = {
  "products-modal": <ProductsModal />,
};

export default function ModalSlot() {
  const params = useSearchParams();
  const modal = params.get("modal");

  return MODAL_COMPONENTS[modal ?? ""] ?? null;
}
  • useSearchParams로 modal 값을 가져와 조건부로 컴포넌트를 렌더링

2. ProductsModal.tsx

"use client";

import Link from "next/link";
import styles from "./styles.module.scss"

export default function ProductsModal() {
  return (
    <div className={styles.modal}>
      <div className={styles.modalContent}>
        <h2>쿼리 기반 모달!!</h2>
        <Link href="/list" replace>닫기</Link> //쿼리기반이니 /list페이지로 닫기 처리
        <ul>
          <li><Link href="/list/1">상세 1</Link></li>
          <li><Link href="/list/2">상세 2</Link></li>
        </ul>
      </div>
    </div>
  );
}

3. 실제 사용하기

"use client";

import Link from "next/link";

export default function ListPage() {
  return (
    <div>
      <h1>MODALS</h1>
      <p><Link href="/list?modal=products-modal">쿼리기반 모달</Link></p>
    </div>
  );
}

그럼 위와 같이 href 내 경로를 지정해주면되는데, default.tsx 에 선언한 key값을 작성해주면 된다.

0개의 댓글