App Routerのファイルベースの機能をページ内で分割する

# はじめに
NextjsのApp Routerは`app`配下のディレクトリ構造でルーティングを行い、そこに様々な状況に応じたUIをファイル名をもとに定義します。

ディレクトリ構造によるルーティングは簡単にいうと、`app/`直下においたファイルは`/`にアクセスしたときのUIとして、`app/dashboard`直下に置いたファイルは`/dashboard`にアクセスしたときのUIとして扱われます。

表示させたいメインのUIを`page`、読み込み中のUIを`loading`、エラー時のUIを`error`、全体のレイアウトのUIを`layout`という名前のファイルに対して定義します。これらを用いて構築されるページは以下のようなReactコンポーネントと同等の内容が描画されます(他にも紹介しなかった状態のUIを定義するファイル名は存在しますし、UIに関連しないが特別に扱われるファイル名も存在します)。

```tsx
<Layout>
  <ErrorBoundary fallback={<Error />}>
    <Suspense fallback={<Loading />}>
      <Page />
    <Suspense>
  <ErrorBoundary>
</Layout>
```
`Layout`は`layout`に定義したコンポーネント、`Error`は`error`に定義したコンポーネント、`Loading`は`loading`に定義したコンポーネント、`Page`は`page`に定義したコンポーネントです。
`Page`コンポーネントより外の部分はよりディレクトリが深いところで引き継がれます。

```tsx
<OuterLayout>
  <ErrorBoundary fallback={<OuterError />}>
    <Suspense fallback={<OuterLoading />}>
      <Layout>
        <ErrorBoundary fallback={<Error />}>
          <Suspense fallback={<Loading />}>
            <Page />
         <Suspense>
        <ErrorBoundary>
      </Layout>
    </Suspense>
  </ErrorBoundary>
</Layout>
```

このようにディレクトリ構造とファイル名を活用するApp Routerですが、`Parallel Routes`と言われる機能があります。これを用いることで同じパスに対する挙動を異なるディレクトリで宣言することができます。

## Paralle Routes
App Routerはディレクトリ構成に従ったルーティングをしますが、ディレクトリ名の形式によって特別な挙動をすることがあります。`Paralle Routes`はそのようなディレクトリ名を特別に扱うことで利用できる機能の1つです。
この機能はディレクトリ名を`@`から始まる名前にすることで有効になります。そのディレクトリに宣言したUIは1つ浅いディレクトリに定義された`layout`で扱えます
`app/@hello`と`app/@world`にUIがそれぞれ宣言されていることを考えます。通常のルーティング通りであればそこ定義したUIは`/@hello`や`/@world`にアクセスしたときに扱われますが、ディレクトリ名が`@`から始まっている場合はこのパスにアクセスできません。代わりに`app`直下にある`layout`ファイルで以下のようにUIを呼び出せます。
```tsx
export default function Layout(props: {
  children: React.ReactNode
  hello: React.ReactNode
  world: React.ReactNode
}) {
  return (
    <html>
      <body>
        {props.children}
        {props.hello}
        {props.world}
      </body>
    </html>
  )
}

```
`app`直下の`layout`が`props`として通常の`children`の他に`/app/@hello`と`/app/@world`に宣言されたUIを`hello`や`world`から受け取リます。受け取る`props`の名前はディレクトリ名から`@`をとったものです。

`Paralle Routes`は`app/@hello/accounts`のように内部でディレクトリを積み重ねてルーティングを構築できます。パスが`/accounts`の画面では`props.hello`の部分に`app/@hello/accounts`で定義したUIが表示されます。

`app/accounts`ディレクトリにファイルを置いて`/accounts`にアクセスしても`app/@hello/accounts`や`app/@world/accounts`にUIが宣言されていない場合は`app`直下の`not-found`ファイルに書かれたUIかデフォルトの404ページが表示されます。ただし、Nextjsの`Link`などのナビゲーション機能を用いて遷移した場合はその部分に直前まで表示していたUIを表示し続けます。
`/accounts`に直接アクセスしたときにUIを表示させたい場合は`app/@hello/accounts`と`app/@world/accounts`にUIを宣言するか、`app/@hello`と`app/@world`に`default`ファイルを宣言させる必要があります。

`default`ファイルは`Paralle Routes`内に定義されていないパスにアクセスしたときに返すデフォルトのUIを宣言するものです。すべてのルートを制御するのは難しいため、`not-found`を返すようにしたいとき以外は`default`ファイルにUIを宣言しておくのが良いと考えています。

### 使い方
ページ内で異なる意味のUIを表示させたい場合に読み込みやエラーの状態を分割するために`Paralle Routes`を利用することが最も簡単なケースです。
```tsx
export default function Layout({
  accounts,
  dashboard,
}: {
  accounts: React.ReactNode
  dashboard: React.ReactNode
}) {

  retrurn (
    <>
      {accounts}
      {dashboard}
    </>
  )
}
```
この例のようにすることで、アカウントに関するUIとダッシュボードに表示するUIを分離して表示させます。

`Paralle Routes`はこの他にも条件によって異なるをUIを出し分ることが可能です。
```tsx
export default function Layout({
  children,
  login,
}: {
  children: React.ReactNode
  login: React.ReactNode
}) {
  const { isLoaded, userId } = useAuth();

  if (!isLoaded || !userId) {
    return login;
  }

  retrurn children
}
```
ログインしている時はユーザーに特化した内容を、ログインしていない場合はログインを促す画面やユーザーに依存していない画面を表示させます。
ログインユーザーに対するルーティングを行うディレクトリとログインしていないユーザーに対するルーティングを行うディレクトリで分割できるところに利点があります。

さらに`Intercepting Routes`と`Paralle Router`を組み合わせて使う方法も有名です。
`Intercepting Routes`についての詳細は紹介しませんが、この機能も特別なディレクトリ名を付けることによって有効になります。`(.)`や`(...)`や`(..)(..)`のようなものが先頭についている場合に利用でき、ルーティングを先頭についた文字列をもとにハックします。
`app/dashboard/(..)photos`というディレクトリがあるとします。`/dashboard`から`/photos`にNextjsの`Link`などを用いた遷移を行った場合に`app/photos`に宣言されたUIの代わりに`app/dashboard/(..)photos`に宣言したUIを表示します。

こんな`Intercepting Routes`は`Paralle Router`と組み合わせてある機能を作ることができます。

```tsx:app/@modal/(..)photos/[id]/pages.tsx
export default function PhotoModal({ photo }) {
  return (
    <Modal>
      <Photo photo={photo} />
    </Modal>
  )
}
```

```tsx:app/photos/[id]/pages.tsx
export default function Photo({ photo }) {
  return <Photo photo={photo} />
}
```

```tsx:app/layout.tsx
export default function Layout({
  children,
  modal,
}: {
  children: React.ReactNode
  modal: React.ReactNode
}) {
  return (
    <>
      {props.children}
      {props.modal}
    </>
  )
}
```

```tsx:app/page.tsx
export default function Photos() {
  return (
    <>
      {photos.map((photo) => (
        <Link key={photo.id} href="/photos/photo.id">
          <Photo photo={photo} />
        </Link>
      )}
    </>
  )
}
```

`app`直下と`@modal`直下には`default`ファイルが置かれており、`null`を返すようになっているとします。
このように定義された時のルーティングは以下のようになります。
`/`にアクセスした時は、`@modal`側は返すものがないので`null`を返し、`app/page.tsx`に宣言されたUIからリンク付きの`Photo`を複数表示させます。
`Photo`にあるリンクを使って`/`から`/photo/:id`にアクセスした時は`app/@modal`に`(..)photo/[id]`が存在するので、`app/photo/[id]`のUIを表示せずに、`app/@modal/(..)photo/[id]`に宣言したUIを表示させます。
`/photo`に直接アクセスした時は`app/@modal`側は`null`を返し、`app/photo/[id]`に宣言したUIが表示されます。
このように組み合わせることで以下のサイトのような機能を作成できます。

https://nextgram.vercel.app/

`Intercepting Routes`と`Paralle Router`を使うことで一覧から詳細へ訪れる時は背景で一覧をちらつかせつつモーダルを表示させ、別の場所や直接のアクセスがあった時は詳細をページ全体に表示させるようなルーティングを簡単に実装できると言うわけです。

## おわりに
`Paralle Routes`を紹介しました。App Routerは直感的なルーティング機能が提供しています。そんな中で命名による特別なルーティングを行うと直感的な部分が損なわれてしますので使い過ぎには気をつけた方が良いです。

例えば、UIの意味によって分けるために利用すると、ルーティングの複雑さに対してメリットが小さいのでこの機能を利用せずにファイル内で`Suspense`や`ErrorBoundary`などの境界を引いて分離した方が良いと考えています。
しかし、ログインの有無によって表示させるコンテンツを切り替えるようなケースでは第2のディレクトリを`Paralle Routes`を用いて記述することで綺麗に切り分けられるので有意義に利用できますし、最後に紹介したようなアクセスのされ方によって表現方法を変えるような実装はこれを使わなければより複雑な実装になってしまうと考えられるのでそのようなケースでは`Paralle Routes`は有効的と考えています。

便利な機能ですが、本当に`Paralle Routes`が有効的か考えてから利用するように注意していきましょう！