デザインについての学習メモブログ

Next.js 入門 #2 : ページとルーティング — ファイルを置くだけでURLができる

記事内に広告が含まれています。

Next.js 入門 #2 : ページとルーティング — ファイルを置くだけでURLができる

前回の記事でNext.jsの開発環境を整えました。

今回はいよいよ「ページを追加する」体験をします。

Next.jsのルーティングは独特で、最初は「え、こんなに簡単でいいの?」と拍子抜けするかもしれません。

設定ファイルを書く必要はありません。

フォルダとファイルを置くだけでURLが生まれます。

App Routerの基本ルール

Next.jsの app/ フォルダは特別な場所です。

ここに page.tsx というファイルを置くと、そのフォルダ構造がそのままURLになります。

Bash
app/
├── page.tsx           localhost:3000/
├── about/
   └── page.tsx       localhost:3000/about
└── blog/
    ├── page.tsx       localhost:3000/blog
    └── first-post/
        └── page.tsx   localhost:3000/blog/first-post

ルールはたったひとつ:ページとして表示したいファイルは page.tsx という名前にする

フォルダ名がそのままURLのパスになります。

直感的ですよね。

実際にページを追加してみる

前回作ったプロジェクト(my-first-nextjs)を開いて、開発サーバーを起動しておいてください。

Bash
npm run dev

Aboutページを作る

app/ の中に about フォルダを作り、その中に page.tsx を作成します。

TSX
// app/about/page.tsx

export default function AboutPage() {
  return (
    <main>
      <h1>このサイトについて</h1>
      <p>Next.jsの練習で作ったサイトです。</p>
    </main>
  );
}

ブラウザで http://localhost:3000/about を開くと、作ったページが表示されます。設定ファイルを一切触らずに、です。

Blogページも作る

同じ要領で app/blog/page.tsx を作ります。

TSX
// app/blog/page.tsx

export default function BlogPage() {
  return (
    <main>
      <h1>ブログ</h1>
      <p>記事一覧がここに並びます。</p>
    </main>
  );
}

http://localhost:3000/blog でアクセスできます。

ページ間をリンクで繋ぐ

ページを作ったら、行き来できるようにしましょう。HTMLでいう <a> タグの代わりに、Next.jsでは <Link> コンポーネントを使います。

TSX
// app/page.tsx(トップページ)

import Link from 'next/link';

export default function Home() {
  return (
    <main>
      <h1>トップページ</h1>
      <nav>
        <Link href="/about">このサイトについて</Link>
        <Link href="/blog">ブログ</Link>
      </nav>
    </main>
  );
}

なぜ <a> ではなく <Link> を使うの?

通常の <a> タグでページ遷移すると、ブラウザがページ全体を再読み込みします。

<Link> を使うと、Next.jsが差分だけを更新するのでページ遷移が高速になります。

また、リンク先のページを事前に読み込んでおく(プリフェッチ)機能も自動で働きます。

基本的に、Next.jsアプリ内のリンクは常に <Link> を使うと覚えておいてください。

動的ルート — URLにIDを含める

ブログ記事一覧を作るとき、/blog/1/blog/2/blog/3 のように記事ごとにURLが変わります。

記事の数だけページファイルを作るのは非現実的ですよね。

そこで使うのが動的ルートです。フォルダ名を角括弧 [...] で囲むと、URLの一部を変数として受け取れます。

Bash
app/
└── blog/
    ├── page.tsx           /blog
    └── [id]/
        └── page.tsx       /blog/1、/blog/2、/blog/abc  なんでも受け取れる

[id] フォルダの中の page.tsx でURLの値を受け取る方法はこうです。

TSX
// app/blog/[id]/page.tsx

type Props = {
  params: Promise<{ id: string }>;
};

export default async function BlogPostPage({ params }: Props) {
  const { id } = await params;

  return (
    <main>
      <h1>記事 #{id}</h1>
      <p>ここに記事の内容が入ります。</p>
    </main>
  );
}

http://localhost:3000/blog/42 にアクセスすると「記事 #42」と表示されます。

/blog/hello-world なら「記事 #hello-world」です。

💡ポイント:

Next.js 15以降、params非同期(Promise)になりました。

await params で値を取り出してから使います。

動的ルートとリンクを組み合わせる

ブログ一覧ページ(/blog)から各記事へリンクを張ってみましょう。

TSX
// app/blog/page.tsx

import Link from 'next/link';

const posts = [
  { id: '1', title: 'Next.jsを始めてみた' },
  { id: '2', title: 'App Routerが便利すぎる件' },
  { id: '3', title: 'Tailwind CSSとの組み合わせ' },
];

export default function BlogPage() {
  return (
    <main>
      <h1>ブログ</h1>
      <ul>
        {posts.map((post) => (
          <li key={post.id}>
            <Link href={`/blog/${post.id}`}>{post.title}</Link>
          </li>
        ))}
      </ul>
    </main>
  );
}

一覧の各リンクをクリックすると、動的ルートのページに飛べます。

今はデータをファイル内に直書きしていますが、後の記事でAPIから取得する方法を紹介します。

存在しないページを開いたら?(404ページ)

/blog/999 にアクセスしたとき、記事が存在しない場合にエラーを表示したいことがあります。

Next.jsには notFound() という関数が用意されています。

TSX
// app/blog/[id]/page.tsx

import { notFound } from 'next/navigation';

const posts: Record<string, string> = {
  '1': 'Next.jsを始めてみた',
  '2': 'App Routerが便利すぎる件',
};

type Props = {
  params: Promise<{ id: string }>;
};

export default async function BlogPostPage({ params }: Props) {
  const { id } = await params;
  const title = posts[id];

  if (!title) {
    notFound(); // 存在しないIDなら404を表示
  }

  return (
    <main>
      <h1>{title}</h1>
    </main>
  );
}

notFound() を呼ぶと、Next.jsが自動で404ページを表示します。

カスタムの404デザインを用意したい場合は app/not-found.tsx を作るだけでOKです。

TSX
// app/not-found.tsx

import Link from 'next/link';

export default function NotFound() {
  return (
    <main>
      <h1>404 — ページが見つかりません</h1>
      <Link href="/">トップページへ戻る</Link>
    </main>
  );
}

ここまでのフォルダ構成

今回作ったファイルをまとめると、こうなっています。

Bash
app/
├── page.tsx               /
├── not-found.tsx          404ページ
├── about/
   └── page.tsx           /about
└── blog/
    ├── page.tsx           /blog
    └── [id]/
        └── page.tsx       /blog/:id

これだけのファイルで5つのルートが機能しています。

設定ファイルは0行です。

まとめ

この記事で学んだこと:

  • app/ フォルダのファイル構造がそのままURLになる(App Router)
  • ページとして表示するファイルは必ず page.tsx という名前にする
  • サイト内のリンクは <Link> コンポーネントを使う(<a> タグではなく)
  • フォルダ名を [id] のように角括弧で囲むと、URLの値を受け取れる(動的ルート)
  • notFound() で404ページを表示でき、not-found.tsx でデザインをカスタマイズできる

次の記事では、全ページ共通のヘッダーやフッターを作るための レイアウト と、コンポーネントの設計について掘り下げます。