Next.js의 Parallel Routes와 Intercepting Routes에 대해 알아보고 이를 프로젝트 적용해 모달을 띄우는 방법으로 회원가입/로그인 화면을 구현해 보았다.
다음과 같이 사용자가 Join Us
버튼을 눌렀을 때 나타나는 회원가입 모달창을 Next.js의 Parallel Routes와 Intercepting Routes를 사용하여 구현해보았다.
먼저, Parallel Routes와 Intercepting Routes의 개념에 대해 알아보자.
동시에 또는 조건에 따라 동일한 레이아웃에서 여러 페이지를(병렬로) 렌더링할 수 있게 해주는 기능으로, 매우 동적인 애플리케이션을 구현할 수 있게 한다.
기본 라우팅 동작을 가로채어 대체 뷰 또는 컴포넌트를 제공할 수 있게 한다. 현재 레이아웃 내에서 다른 부분의 경로를 로드할 수 있다. 이를 통해 모달, 드로어 등과 같은 고급 라우팅 패턴을 구현할 수 있다.
여기에서는
한 레이아웃 내에서 여러 페이지(회원가입, 로그인 페이지)를 조건부로 렌더링하기 위해 Parallel Routes를 사용할 것이다.
위에 사진을 통해 알 수 있듯이,
같은 레이아웃 안에서
/signup
으로 접속했을 때에는 회원가입 모달 창을 띄우고/login
으로 접속했을 때에는 로그인 모달 창을 띄우게 하려는 것이다.
export default function Home() {
return (
<main>
<Link href="/signup">
<Button>Join Us</Button>
</Link>
<Link href="/login">
<Button variant="link">Already have an account?</Button>
</Link>
</main>
);
}
이렇게 버튼을 클릭했을 때 Link 태그를 통해 해당 주소로 이동하도록 구현해준다.
이때, Intercepting Routes를 함께 사용해서 구현하는데,
각각의 주소에 해당하는(/signup
, /login
) 모달 창의 내용을 현재 페이지의 레이아웃을 유지하면서 로드하기 위해서이다.
- 모달 창의 내용을 URL을 통해 공유 가능
- 페이지를 새로고침(hard refreshing)했을 때에도 모달 창이 꺼지지 않고 유지 가능
- 뒤로 가기/앞으로 가기를 통해 모달창을 열고 닫기 가능
(참고) 폴더 구조는 다음과 같다.
먼저, 슬롯 폴더를 생성해준다. (signup 페이지를 기준으로 설명. login 페이지도 같은 방식으로 생성하면 됨.)
'@'을 사용해서 폴더를 만들면, 해당 폴더는 슬롯으로 동작한다.
슬롯은 특정 경로에 콘텐츠를 삽입할 수 있는 "플레이스홀더" 역할을 한다.
여기서 이 슬롯은 실제 URL 구조에 영향을 주지 않는다. 즉, URL 경로에 슬롯 이름이 포함되지 않는다는 것이다.
폴더 구조가 다음과 같을 때,
/app
/@auth
/(.)signup
page.tsx
@auth
폴더는 슬롯 폴더이다.
@auth/(.)signup
은 /signup
경로에서 접근할 수 있다.
즉, /app/@auth/(.)signup/page.tsx
파일의 내용은 /members
URL에서 보여지게 된다.
그리고 layout.tsx
파일에서 {auth}
를 통해 auth 슬롯의 콘텐츠를 렌더링한다.
export default function RootLayout({
children,
auth,
}: Readonly<{
children: React.ReactNode;
auth: React.ReactNode;
}>) {
return (
<html lang="en" suppressHydrationWarning={true}>
<body className={inter.className}>
{children}
{auth} {/* auth 슬롯의 콘텐츠를 여기서 렌더링 */}
</body>
</html>
);
}
이렇게 생성한 슬롯 폴더 안에 경로에 대한 페이지를 정의하는 폴더인 (.)signup
폴더를 생성해준다.
(.)으로 시작하는 폴더를 통해 URL 경로 세그먼트를 정의할 수 있다.
ex) app/(.)dashboard
폴더는 /dashboard
경로에 매핑됨.
이 폴더 안에 page.tsx
파일을 생성해서 /signup
경로에 해당하는 페이지를 만들어준다.
export default function Page() {
return <SignupCard />;
}
나는 여기에 모달 형태의 회원가입 창인<SignupCard />
컴포넌트를 넣어줬다.
로그인 창도 회원가입 창과 같이 만들어준다.
그리고 실제 경로를 만들기 위해 @auth
슬롯 폴더 안에서 말고, app
안에서 폴더를 생성하고, 그에 맞는 페이지를 만들어줘야 한다. (*이걸 안해줘서 문제가 생겼었다..)
/app
/signup
page.tsx
/login
page.tsx
여기에서 page.tsx
파일 안의 내용은 슬롯 폴더 안의 내용과 똑같이 작성해준다.
그리고 또 중요한 default.tsx
파일을 생성해준다.
모달이 비활성화되었을 때 모달의 내용이 렌더링되지 않도록 하기 위해 null을 반환하는 default 파일을 생성해준다.
주소창 입력 통해서 모달창에 접근 가능, 새로고침 시 모달 창 유지