並列ルーティング
並列ルーティングを使用すると、同じレイアウト内で1つ以上のページを同時に、または条件付きでレンダリングできます。これらは、ダッシュボードやソーシャルサイトのフィードなど、アプリの非常に動的なセクションに役立ちます。
たとえば、ダッシュボードを考えると、並列ルーティングを使用してteam
ページとanalytics
ページを同時にレンダリングできます。

スロット
並列ルートは、名前付きの**スロット**を使用して作成されます。スロットは@folder
規約で定義されます。たとえば、以下のファイル構造では、@analytics
と@team
の2つのスロットが定義されています。

スロットは、共有親レイアウトにプロパティとして渡されます。上記の例では、app/layout.js
内のコンポーネントは@analytics
と@team
のスロットプロパティを受け入れ、children
プロパティと並行してそれらをレンダリングできます。
export default function Layout({
children,
team,
analytics,
}: {
children: React.ReactNode
analytics: React.ReactNode
team: React.ReactNode
}) {
return (
<>
{children}
{team}
{analytics}
</>
)
}
ただし、スロットはルーティングセグメント**ではなく**、URL構造には影響しません。たとえば、/@analytics/views
の場合、@analytics
はスロットなのでURLは/views
になります。スロットは通常のPageコンポーネントと組み合わされて、ルーティングセグメントに関連付けられた最終ページを形成します。このため、同じルーティングセグメントレベルで個別の静的スロットと動的スロットを持つことはできません。1つのスロットが動的である場合、そのレベルのすべてのスロットも動的である必要があります。
ご存じの通り:
children
プロパティは、フォルダにマッピングする必要のない暗黙のスロットです。つまり、app/page.js
はapp/@children/page.js
と同じです。
アクティブ状態とナビゲーション
デフォルトでは、Next.js は各スロットのアクティブな**状態** (またはサブページ) を追跡します。ただし、スロット内でレンダリングされるコンテンツは、ナビゲーションの種類によって異なります。
- **ソフトナビゲーション**: クライアントサイドナビゲーション中、Next.js は部分的なレンダリングを実行し、スロット内のサブページを変更しながら、現在のURLと一致しない場合でも他のスロットのアクティブなサブページを維持します。
- **ハードナビゲーション**: フルページロード (ブラウザのリフレッシュ) 後、Next.js は現在の URL と一致しないスロットのアクティブ状態を判別できません。代わりに、一致しないスロットには
default.js
ファイルがレンダリングされ、default.js
が存在しない場合は404
がレンダリングされます。
ご存じの通り:
- 一致しないルートに対する
404
は、意図しないページに並列ルートが誤ってレンダリングされるのを防ぐのに役立ちます。
default.js
初期ロード時またはフルページリロード時に、一致しないスロットのフォールバックとしてレンダリングするために、`default.js`ファイルを定義できます。
次のフォルダ構造を検討してください。@team
スロットには/settings
ページがありますが、@analytics
にはありません。

/settings
に移動すると、@team
スロットは/settings
ページをレンダリングし、@analytics
スロットの現在アクティブなページを維持します。
更新すると、Next.jsは@analytics
にdefault.js
をレンダリングします。default.js
が存在しない場合、代わりに404
がレンダリングされます。
さらに、children
は暗黙のスロットであるため、Next.jsが親ページのアクティブな状態を復元できない場合に、children
のフォールバックをレンダリングするためにdefault.js
ファイルを作成する必要があります。
useSelectedLayoutSegment(s)
useSelectedLayoutSegment
とuseSelectedLayoutSegments
の両方ともparallelRoutesKey
パラメータを受け入れ、これによりスロット内のアクティブなルートセグメントを読み取ることができます。
'use client'
import { useSelectedLayoutSegment } from 'next/navigation'
export default function Layout({ auth }: { auth: React.ReactNode }) {
const loginSegment = useSelectedLayoutSegment('auth')
// ...
}
ユーザーがapp/@auth/login
(またはURLバーの/login
)にナビゲートすると、loginSegment
は文字列"login"
と等しくなります。
例
条件付きルート
並列ルートを使用して、ユーザーロールなどの特定の条件に基づいてルートを条件付きでレンダリングできます。たとえば、/admin
または/user
ロールに対して異なるダッシュボードページをレンダリングする場合などです。

import { checkUserRole } from '@/lib/auth'
export default function Layout({
user,
admin,
}: {
user: React.ReactNode
admin: React.ReactNode
}) {
const role = checkUserRole()
return role === 'admin' ? admin : user
}
タブグループ
スロット内にlayout
を追加することで、ユーザーがスロットを独立してナビゲートできるようにできます。これはタブを作成するのに役立ちます。
たとえば、@analytics
スロットには/page-views
と/visitors
という2つのサブページがあります。

@analytics
内で、2つのページ間でタブを共有するためのlayout
ファイルを作成します。
import Link from 'next/link'
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<>
<nav>
<Link href="/page-views">Page Views</Link>
<Link href="/visitors">Visitors</Link>
</nav>
<div>{children}</div>
</>
)
}
モーダル
並列ルートは、インターセプティングルートと組み合わせて使用することで、ディープリンクをサポートするモーダルを作成できます。これにより、モーダルを構築する際の一般的な課題を解決できます。例えば:
- モーダルのコンテンツを**URL経由で共有可能にする**。
- モーダルを閉じる代わりに、ページを更新しても**コンテキストを保持する**。
- 前のルートに戻るのではなく、**戻るナビゲーションでモーダルを閉じる**。
- 進むナビゲーションでモーダルを再度開く.
以下のUIパターンを考えてみましょう。ユーザーはクライアントサイドナビゲーションを使用してレイアウトからログインモーダルを開くことも、個別の/login
ページにアクセスすることもできます。

このパターンを実装するには、まず**メインの**ログインページをレンダリングする/login
ルートを作成します。

import { Login } from '@/app/ui/login'
export default function Page() {
return <Login />
}
次に、@auth
スロット内にnull
を返すdefault.js
ファイルを追加します。これにより、モーダルがアクティブでないときにレンダリングされないようにします。
export default function Default() {
return null
}
@auth
スロット内で、/(.)login
フォルダを更新して/login
ルートをインターセプトします。<Modal>
コンポーネントとその子を/(.)login/page.tsx
ファイルにインポートします。
import { Modal } from '@/app/ui/modal'
import { Login } from '@/app/ui/login'
export default function Page() {
return (
<Modal>
<Login />
</Modal>
)
}
ご存じの通り
- ルートをインターセプトするために使用される規約、例えば
(.)
は、ファイルシステムの構造によって異なります。インターセプティングルートの規約を参照してください。<Modal>
の機能とモーダルコンテンツ(<Login>
)を分離することで、モーダル内のコンテンツ、例えばフォームなどがサーバーコンポーネントであることを保証できます。詳細については、クライアントコンポーネントとサーバーコンポーネントのインターリーブを参照してください。
モーダルの開閉
これで、Next.jsルーターを活用してモーダルを開閉できます。これにより、モーダルが開いているとき、および前後にナビゲートするときに、URLが正しく更新されます。
モーダルを開くには、@auth
スロットを親レイアウトにプロパティとして渡し、children
プロパティと並行してレンダリングします。
import Link from 'next/link'
export default function Layout({
auth,
children,
}: {
auth: React.ReactNode
children: React.ReactNode
}) {
return (
<>
<nav>
<Link href="/login">Open modal</Link>
</nav>
<div>{auth}</div>
<div>{children}</div>
</>
)
}
ユーザーが<Link>
をクリックすると、/login
ページに移動する代わりにモーダルが開きます。ただし、更新または初期ロード時に/login
に移動すると、ユーザーはメインのログインページに移動します。
モーダルの閉じる
モーダルはrouter.back()
を呼び出すか、Link
コンポーネントを使用することで閉じることができます。
'use client'
import { useRouter } from 'next/navigation'
export function Modal({ children }: { children: React.ReactNode }) {
const router = useRouter()
return (
<>
<button
onClick={() => {
router.back()
}}
>
Close modal
</button>
<div>{children}</div>
</>
)
}
Link
コンポーネントを使用して、もはや@auth
スロットをレンダリングすべきではないページから移動する場合、並列ルートがnull
を返すコンポーネントと一致することを確認する必要があります。たとえば、ルートページに戻る場合、@auth/page.tsx
コンポーネントを作成します。
import Link from 'next/link'
export function Modal({ children }: { children: React.ReactNode }) {
return (
<>
<Link href="/">Close modal</Link>
<div>{children}</div>
</>
)
}
export default function Page() {
return null
}
または、他のページ(/foo
、/foo/bar
など)にナビゲートする場合は、キャッチオールスロットを使用できます。
export default function CatchAll() {
return null
}
ご存じの通り
- アクティブ状態とナビゲーションで説明されている動作のため、モーダルを閉じるには
@auth
スロットでキャッチオールルートを使用します。スロットに一致しなくなったルートへのクライアントサイドナビゲーションは表示されたままになるため、モーダルを閉じるにはスロットをnull
を返すルートに一致させる必要があります。- その他の例としては、ギャラリーで写真モーダルを開きながら専用の
/photo/[id]
ページを持つ場合や、サイドモーダルでショッピングカートを開く場合などが考えられます。- インターセプトされた並列ルートを持つモーダルの例を見る
読み込みとエラーUI
並列ルーティングは独立してストリーミングできるため、各ルートに独立したエラー状態と読み込み状態を定義できます。

お役に立ちましたか?