# [Next.js] parallel routes & intercepting routes

트위터 로그인 모달창을 만들어보며 넥스트의 parallel routes 와 intercepting routes 을 학습한 내용을 정리해보았습니다.

트위터 로그인 창을 확인해봅시다.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1706749133821/6ebdcd31-9d1c-4529-a9de-5d79607fa7de.png align="center")

루트 디렉토리 화면을 배경으로 i/flow/login 페이지가 동시에 표시되고 있습니다.

저는 app router 를 학습하기 전까지는 createPortal 을 사용하여 포탈 영역에 로그인 컴포넌트를 띄우는 방식을 사용했었습니다.

```javascript
const NoLogin =()=>{

    let [loginModal, setLoginModal] = useState<boolean>(false);
    let [signupModal, setsignupModal] = useState<boolean>(false);
  
  
    const loginModalHandler = useCallback((sign:boolean)=>{
        setLoginModal(sign);
    }, [])
  
    const SignupModalHandler = useCallback((sign:boolean)=>{
      setsignupModal(sign);
  }, [])

    return(
       {/* 생략 */}
        <div className="pt-6">
          <Link href='/' as='/i/flow/login' scroll={false}>
            <button className="rounded-2xl border-2 p-2" onClick={()=>{loginModalHandler(true)}}>
              로그인
            </button>
          </Link>
          {loginModal && createPortal(<LoginModal loginModalHandler={()=>{loginModalHandler(false)}}/>, document.body)}
      </div>
    {/* 생략 */}
)
```

href 경로와 as 경로를 달리해 뒷배경으로 메인 화면을 띄우고 그 위에 로그인 모달을 띄우는 데 성공했습니다. 하지만 이 방식은 loginModal state 를 정의해서 modal 의 상태를 계속 감시해야하는 번거로움이 있습니다.

Next.js app router 를 학습하며, 모달창을 쉽게 구현하도록 해주는 기능이 내재되어있다는 것을 알게되었고, 위의 createPortal 방식을 넥스트의 parallel routes, intercepting routes 를 활용한 모달창 방식으로 바꿔보고자 하였습니다.

---

## parallel routes

하나의 레이아웃에서 여러 페이지를 동시에 보여줄 수 있는 기능입니다. slots(`@folderName`)에 의해 생성이 되며, 이렇게 생성된 slot 속 페이지는 slot과 같은 레벨의 레이아웃에 props 로 전달됩니다. (이 때, slot 폴더는 url 에 영향을 주지 않고 무시됩니다.)

넥스트 앱라우터 공식 문서를 참고하며 parallel routes 에 대해 자세히 알아봅시다.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1706752792590/9318f0b9-159f-4f15-84f0-5221bd7f53b7.png align="center")

`@analytics` 와 `@team` 이라는 slot 이 생성되었습니다. 이들은 모두 같은 레벨의 레이아웃에 props 로 다음과 같이 전달되어 렌더링됩니다.

```jsx
export default function Layout({
  children,
  team,
  analytics,
}: {
  children: React.ReactNode
  analytics: React.ReactNode
  team: React.ReactNode
}) {
  return (
    <>
      {children}
      {team}
      {analytics}
    </>
  )
}
```

자 이제 다시 트위터로 돌아가겠습니다. app router 의 파일 컨벤션에 따라서 app 디렉토리에 다음과 같은 폴더 구조를 생성했습니다.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1706752964242/117ac8a4-2b83-4b20-836b-6d5d3d29450e.png align="center")

폴더구조를 잘 살펴봅시다. 같은 레이아웃을 공유해야한다는 것, 그것에 따라 폴더 구조를 정렬해야한다는 것을 이해해야 합니다.

`@modal` 은 props 의 **modal**로 전달이 되었고, 그 외 요소들은 **children**로 전달이 되었습니다. 그 후 매칭되는 라우트에 네비게이션할 때 해당 라우팅의 컴포넌트가 렌더링됩니다.

slot 을 따라 레이아웃을 다음과 같이 구성했습니다.

```tsx
import { ReactNode } from "react"

export default function Layout({children, modal}:{children: ReactNode, modal:ReactNode}){
    return(
        <div>
            {children}
            {modal}
        </div>
    )
}
```

이제 `baseURL/i/flow/login` 으로 접속 시 children 부분에는 `(beforeLogin)/i/flow/login` 이, modal 부분에는 `(beforeLogin)/@modal/i/flow/login` 이 매핑됩니다.

그렇다면 `baseURL/` 로 접속한다면?

children 부분에는 `page.tsx` 가 매핑되고, modal 부분에는 `default.tsx` 가 매핑됩니다. (`@modal/page.tsx` 부재를 `default.tsx` 가 대체)

> `default.tsx` → parallel route 의 default page. parallel route 가 이용되지 않을 때 이 페이지를 디폴트값으로 띄워줍니다. 즉, 라우팅이 unmatched 할 때 이 페이지를 렌더링합니다. (따라서 위와 같은 상황에 default.tsx 페이지가 없다면 에러가 발생하겠지요.)

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1706753553302/7855b07f-56cd-49df-bde6-0ce509ba05f2.png align="center")

하지만 우리가 원하는 것은 `i/flow/login/page.tsx` 가 동시에 렌더링 되는 것이 아닙니다.. 우리가 원하는 것은 main page(라우팅 주소가 다름)가 뒷배경으로 렌더링 되는 것! 페이지를 동시에 띄우는 것까지 했으니, 주소가 다른 페이지를 렌더링하는 작업을 해보도록 하겠습니다.

## Intercepting routes

intercepting routes 는 현재 페이지 컨텍스트를 유지한 채로 새로운 라우트를 렌더링합니다. 따라서 주소가 다른 페이지들을 동시에 렌더링 하고자 할 때 유용합니다.

원하는 화면을 구성하기 위해 layout props 로 **children** 을 `page.tsx` 로, **modal** 을 `@modal/i/flow/login/page.tsx` 로 전달해봅시다.

interception routes 는 `(..)` 와 같은 컨벤션으로 정의됩니다.

* `(.)` 동일한 라우팅 레벨 세그먼트에 매칭
    
* `(..)` 부모 라우팅 레벨 세그먼트에 매칭
    
* `(..)(..)` 2단계 윗 레벨
    
* `(…)` app 디렉토리 루트 요소에 매칭
    

> 💡 주의할 것은, 기준이 브라우저 주소라는 것입니다! (라우트 세그먼트 기준)

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1706754307341/95430172-8acb-45d7-9427-4a35c6a9cbad.png align="center")

구조를 위와 같이 바꿔 intercepting routes 를 사용해보았습니다.

다시 구조를 살펴보면, `@modal` 은 라우팅에 영향을 미치지 않는 slot이지, 라우트 세그먼트가 아닙니다. 그렇기 때문에 `@modal` 요소 컨텍스트는 유지한 채 (브라우저 주소 상)같은 레벨의 i 요소의 라우팅을 인터셉트할 수 있습니다. ((..)i 로 폴더 이름을 바꾸는 실수를 저지르면 안됩니다.)

이제 `layout.tsx` 에 children prop 에 `page.tsx` 가 렌더링되고, modal prop에 `i/flow/login` 으로 인터셉트한 기존 모달 부분이 렌더링되어 원하던 결과를 얻을 수 있게 됩니다.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1706754478047/890c3550-2f6d-4a35-84fc-df8fd5ef3f16.png align="center")

([localhost:3000/i/flow/login](http://localhost:3000/i/flow/login) 화면)

이렇게 모달을 만들면 좋은 점은 다음과 같습니다. (공식문서 참조)

* 뒤로가기/앞으로 가기로 모달을 열고 닫을 수 있음
    
* URL 통해 모달 내용 공유 가능
    
* 페이지 새로고침 시 모달이 닫히는 대신 컨텍스트가 유지됨
    

즉, 페이지를 모달로 띄우기가 가능해 모달 자체가 url 로 관리될 수 있다는 것입니다. createPortal 보다 방법이 직관적이고 간단해서 좋은 것 같습니다.

---

### 번외..

왜 인터셉트 후, `page.tsx`가 children 으로, `@modal/i/flow/login/page.tsx` 가 modal 로 렌더링되는가?

저는 위 사항이 이해가 가지 않았습니다. parallel routes 는 매칭되는 라우팅에 해당하는 여러 페이지를 동시에 보여준다고 이해했는데, 둘은 매칭되는 라우팅 주소가 다른데 어떻게 동시에 렌더링이 되는 것일까요.

공식문서에 의하면 기본적으로 슬롯에서 렌더링되는 컨텐츠는 현재 url 과 매치됩니다. 그런데 매치되지 않는 슬롯이 있는 경우는 다음과 같이 페이지를 렌더링한다고 합니다.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1706754827572/63495109-545d-4c0d-8db2-abab615c314c.png align="center")

위는 라우팅이 통일되지 않았습니다. 여기서 /settings 로 이동하는 상황을 가정해보면, @analytics 는 어떤 페이지를 보내줘야할까요?

|  | `@analytics/default.js` 가 존재하는 경우 | `@analytics/default.js` 가 존재하지 않는 경우 |
| --- | --- | --- |
| 소프트 네비게이션 | `@team/settings/page.js` 그리고 `@analytics/page.js` | `@team/settings/page.js` 그리고 `@analytics/page.js` |
| 하드 네비게이션 | `@team/settings/page.js` 그리고 `@analytics/default.js` | 404 |

**Softe navigation:** 변화된 segments들의 캐시 사용

**Hard Navigation:** 세그먼트 리렌더링, 데이터 refetch

(출처: [https://velog.io/@glassfrog8256/번역-Next.js13-App-Router-Routing-Parallel-Routes](https://velog.io/@glassfrog8256/번역-Next.js13-App-Router-Routing-Parallel-Routes)[)](https://velog.io/@glassfrog8256/%EB%B2%88%EC%97%AD-Next.js13-App-Router-Routing-Parallel-Routes)

기본적으로 브라우저는 하드 네비게이션으로 동작하지만, 넥스트 앱라우터는 소프트 네비게이션을 제공합니다. 위에서 제가 느꼈던 의문은 기존 하드 네비게이션 방식이 아닌 소프트 네비게이션 방식으로 페이지 이동이 이루어졌기 때문인 것 같습니다. 아직 정확히 넥스트에서 어떤 기준으로 soft navigation 을 사용하고, hard navigation 을 사용하는지는 모르겠습니다. 추후에 관련 내용을 추가해보고자 합니다.

오류 / 번외 관련 내용은 댓글로 알려주시면 감사하겠습니다.

[참고 자료:](https://velog.io/@glassfrog8256/%EB%B2%88%EC%97%AD-Next.js13-App-Router-Routing-Parallel-Routes)

[https://rocketengine.tistory.com/entry/NextJS-13-Routing-Intercepting-Routes라우트-가로채기](https://rocketengine.tistory.com/entry/NextJS-13-Routing-Intercepting-Routes라우트-가로채기)

[https://nextjs.org/docs/app/building-your-application/routing/parallel-routes](https://nextjs.org/docs/app/building-your-application/routing/parallel-routes)

[https://nextjs.org/docs/app/building-your-application/routing/intercepting-routes](https://nextjs.org/docs/app/building-your-application/routing/intercepting-routes)
