ルーティング
App Routerのファイルベースルーティング
基本のルーティング
フォルダ = URL
app/以下のフォルダ構造がURLになる
plaintext
app/
├── page.tsx → /
├── about/
│ └── page.tsx → /about
├── blog/
│ └── page.tsx → /blog
└── contact/
└── page.tsx → /contactプレビュー
フォルダ作成 → URL自動生成
// 設定ファイル不要!
動的ルーティング
[param] で動的セグメント
パラメータを含むURL
typescript
// app/blog/[slug]/page.tsx
interface Props {
params: { slug: string }
}
export default function BlogPost({ params }: Props) {
// /blog/hello-world → params.slug = "hello-world"
// /blog/nextjs-tutorial → params.slug = "nextjs-tutorial"
return <h1>記事: {params.slug}</h1>;
}プレビュー
/blog/[slug]/page.tsx
/blog/hello → slug = "hello"
/blog/world → slug = "world"
複数のパラメータ
ネストした動的セグメント
typescript
// app/shop/[category]/[product]/page.tsx
interface Props {
params: {
category: string;
product: string;
}
}
export default function ProductPage({ params }: Props) {
// /shop/electronics/iphone
// → category = "electronics", product = "iphone"
return (
<div>
<p>カテゴリ: {params.category}</p>
<p>商品: {params.product}</p>
</div>
);
}プレビュー
/shop/[category]/[product]
// /shop/clothes/shirt
// category="clothes", product="shirt"
[...slug] キャッチオール
複数のセグメントをまとめてキャッチ
typescript
// app/docs/[...slug]/page.tsx
interface Props {
params: { slug: string[] }
}
export default function DocsPage({ params }: Props) {
// /docs/getting-started
// → slug = ["getting-started"]
// /docs/api/reference/auth
// → slug = ["api", "reference", "auth"]
return <p>パス: {params.slug.join("/")}</p>;
}プレビュー
/docs/[...slug]/page.tsx
// /docs/a/b/c → ["a", "b", "c"]
ルートグループ
(folder) でグループ化
URLに影響せずにフォルダを整理
plaintext
app/
├── (marketing)/
│ ├── about/page.tsx → /about
│ └── contact/page.tsx → /contact
├── (shop)/
│ ├── products/page.tsx → /products
│ └── cart/page.tsx → /cart
└── (auth)/
├── login/page.tsx → /login
└── signup/page.tsx → /signupプレビュー
// (marketing) はURLに含まれない
/about ← (marketing)/about
/login ← (auth)/login
ナビゲーション
Link コンポーネント
クライアントサイドナビゲーション
typescript
import Link from 'next/link';
export default function Navigation() {
return (
<nav>
<Link href="/">ホーム</Link>
<Link href="/about">概要</Link>
<Link href="/blog/hello-world">記事</Link>
{/* 動的パラメータ */}
<Link href={`/blog/${slug}`}>動的リンク</Link>
{/* スクロール位置を維持しない */}
<Link href="/page" scroll={false}>リンク</Link>
</nav>
);
}プレビュー
useRouter (プログラム的遷移)
ボタンクリック等での遷移
typescript
'use client';
import { useRouter } from 'next/navigation';
export default function LoginButton() {
const router = useRouter();
const handleLogin = async () => {
// ログイン処理...
// 成功したらダッシュボードへ
router.push('/dashboard');
// 履歴を置き換え(戻るボタンで戻れない)
router.replace('/dashboard');
// 前のページに戻る
router.back();
// ページをリロード
router.refresh();
};
return <button onClick={handleLogin}>ログイン</button>;
}プレビュー
router.push('/path') // 遷移
router.replace('/path') // 置き換え
router.back() // 戻る
特殊ファイル
page.tsx ルートのUIを定義
layout.tsx 共有レイアウト
loading.tsx ローディングUI
error.tsx エラーUI
not-found.tsx 404ページ
template.tsx 再レンダリングするレイアウト