Skip to content

9. parallel routes

Page ごとに Header を変更する

下記のように、Page ごとに Header を変更できるようにしてみましょう。

inboxdraft
inboxdraft

今回は、parallel routes を利用して、Page ごとに Header を変更する方法を紹介します。

実装する

apps/workspace/app/(dashboard)/layout.tsx を下記のように変更します

// apps/workspace/app/(dashboard)/layout.tsx
export default function dashboardLayout(props: {
children: React.ReactNode;
header: React.ReactNode;
}) {
return (
<main className="relative">
<div className="p-8 h-dvh">
<div className="flex items-center justify-between">
<h1 className="text-4xl font-extrabold tracking-tight">
The Joke Mail Service
{props.header}
</h1>
<form action={logout}>

次に、apps/workspace/app/(dashboard)/@header/inbox/page.tsxを新規で作成します。

Terminal window
mkdir -p "apps/workspace/app/(dashboard)/@header/inbox"
touch "apps/workspace/app/(dashboard)/@header/inbox/page.tsx"
export default function Header() {
return "The Joke Mail Service | Inbox";
}

この時点で、http://localhost:3000/inbox にアクセスすると、Header が The Joke Mail Service | Inbox に変更されます。

つぎに、http://localhost:3000/drafts にアクセスしてみてください。404エラーが表示されると思います。

これは、@headers という形で分割された先にPageが存在しないためです。

draftも同様に追加してみましょう。

Terminal window
mkdir -p "apps/workspace/app/(dashboard)/@header/drafts"
touch "apps/workspace/app/(dashboard)/@header/drafts/page.tsx"
export default function Header() {
return "The Joke Mail Service | Drafts";
}

これで http://localhost:3000/drafts にアクセスしても、404が表示されなくなったと思います。

ここで「すべてのページに追加しなければならないのか?」と思うかもしれません。

実は、存在しないPageにアクセスした場合のために、default.tsx をつかって、デフォルトのHeaderを表示することができます。

実際にdefault.tsx を作成してみましょう。

Terminal window
touch "apps/workspace/app/(dashboard)/@header/default.tsx"
export default function Header() {
return "The Joke Mail Service";
}

これで、http://localhost:3000/sentにアクセスした場合には、The Joke Mail Service が表示されるようになっていると思います。

parallel routes の仕様について理解する

ここで少し不思議な現象を確認してみましょう。

まず、http://localhost:3000/inbox にアクセスしてみてください。

その後、サイドバーから、`Sent` Button クリックして、http://localhost:3000/sent にアクセスしてみてください。

すると、Header が The Joke Mail Service | Inbox のまま変更されないことを確認できると思います。

また、その場でリロード(または、直接アクセス)すると、Header が The Joke Mail Service に変更されることを確認できると思います。

これは parallel routes の仕様です。

ソフトナビゲーション(Next Link)では、遷移先の URL と一致するサブページ(今回でいうと@header/sent/page.tsx)がなくても、現在のサブページを維持して遷移します。

ハードナビゲーション(ブラウザーのリロードや直接アクセスされた時) では、 URL と一致するサブページがない場合は、default.js が表示されます。default.js がない場合は、404 が表示されます。

「結局すべてのページに追加しなければならないのか?」と思うかもしれません。

catch-all route を使うことで解決することができます。

catch-all route は、[...catchAll]/page.tsx という形で指定することができます。どれにもマッチしない場合はこのページが表示されます。 これは、default.tsx よりも優先されます。

Terminal window
mkdir -p "apps/workspace/app/(dashboard)/@header/[...catchAll]"
touch "apps/workspace/app/(dashboard)/@header/[...catchAll]/page.tsx"
//apps/workspace/app/(dashboard)/@header/[...catchAll]/page.tsx
export default function Header() {
return "The Joke Mail Service";
}

これで、http://localhost:3000/sentにアクセスした場合には、The Joke Mail Service が表示されるようになっていると思います。

まとめ

今回は、parallel routes を利用して、Page を分割する方法を紹介しました。

parallel routes を利用することで、Layout をより柔軟に設計することができます。

Next.js 15 rc

Next.js 15 rc では、parallel routes でも chatch-all route の path params を引数として受け取ることができるようになりました。

Terminal window
cd apps/solution/
pnpm install next@rc react@rc react-dom@rc
cd ../../
pnpm dev
//apps/solution/app/(dashboard)/@header/[...catchAll]/page.tsx
export default function Header(props: { params: { catchAll: string[] } }) {
return `The Joke Mail Service | ${props.params.catchAll.join(' | ')}`;
}