Next.jsによるWebアプリケーション開発概論

URL設計を考える:一覧ページと詳細ページを作る

4おすすめスポット共有アプリを作りながら学ぶ 画面遷移設計・状態管理・ユーザー入力処理
Next.jsTailwind CSSアプリ開発開発Web開発

はじめに

この節では、Webアプリでとても大事な URL設計 を学びます。

URLとは、かんたんに言うと ページの住所 です。

たとえば、次のようなURLがあります。

/spots
/spots/1
/spots/2

このURLを見ただけで、

/spots    → スポット一覧ページ
/spots/1  → IDが1のスポット詳細ページ
/spots/2  → IDが2のスポット詳細ページ

とわかるようにします。


この節のゴール

この節では、次のことができるようになることを目指します。

  • /spots が一覧ページだとわかる
  • /spots/[id] が詳細ページだとわかる
  • URLと画面内容の関係を説明できる
  • わかりやすいURLを考えられる
  • 実際に一覧ページと詳細ページを作れる まずは、URLは画面の住所 と覚えてください。

1. 今回作るページ

今回作るのは、次の2つです。

/spots
/spots/[id]

それぞれの役割はこうです。

URL画面役割
/spotsスポット一覧ページすべてのスポットを見る
/spots/[id]スポット詳細ページ1つのスポットを詳しく見る

/spots** とは**

/spots は、スポット一覧ページ です。

ここには、投稿されたスポットをまとめて表示します。

たとえば、

  • 静かな図書館
  • おしゃれカフェ
  • 学食の穴場席

のように、複数のスポットを並べます。


/spots/[id]** とは**

/spots/[id] は、スポット詳細ページ です。

[id] には、スポットごとのIDが入ります。

たとえば、こうです。

/spots/1
/spots/2
/spots/3

これは、それぞれ違うスポットの詳細ページです。


2. URLと画面内容の関係

URLは、そのページが 何の情報を表示しているか を表します。

たとえば、次のように考えます。

/spots
→ スポットを一覧で見る画面

/spots/1
→ IDが1のスポットを詳しく見る画面

つまり、URLを見ただけで、何のページなのか予想できることが大切です。


わかりやすいURLの例

よいURLは、短くて意味がわかります。

/spots
/spots/1
/spots/new

それぞれ、なんとなく意味がわかります。

/spots      → スポット一覧
/spots/1    → スポットID 1 の詳細
/spots/new  → 新規投稿

わかりにくいURLの例

逆に、次のようなURLは少しわかりにくいです。

/page1
/list123
/detaildata
/aaa/bbb/ccc

なぜなら、URLを見ても何のページかわかりにくいからです。

初心者のうちは、短く・意味がある英単語 を使うのがおすすめです。


3. Next.jsでのURLの作り方

Next.js の App Router では、フォルダ構成がURLになります

たとえば、このように作ります。

app
├─ page.tsx
└─ spots
   ├─ page.tsx
   └─ [id]
      └─ page.tsx

これが、次のURLになります。

app/page.tsx
→ /

app/spots/page.tsx
→ /spots

app/spots/[id]/page.tsx
→ /spots/1 など

4. まず一覧ページを作る

まずは /spots のページを作ります。

作るファイル

app/spots/page.tsx

まだ spots フォルダがない場合は、app の中に作ってください。

app
└─ spots
   └─ page.tsx

app/spots/page.tsx

import Link from 'next/link';

type Spot = {
  id: string;
  name: string;
  category: string;
  location: string;
};

const spots: Spot[] = [
  {
    id: '1',
    name: '静かな図書館',
    category: '図書館',
    location: '名古屋駅 徒歩5分',
  },
  {
    id: '2',
    name: 'おしゃれカフェ',
    category: 'カフェ',
    location: '栄駅 徒歩3分',
  },
  {
    id: '3',
    name: '学食の穴場席',
    category: '学食',
    location: '名城大学 2号館',
  },
];

/**
 * 役割: スポット一覧ページを表示する
 * 入力: なし
 * 出力: スポット一覧画面
 */
export default function SpotsPage(): JSX.Element {
  return (
    <main style={{ padding: '32px' }}>
      <h1>スポット一覧</h1>
      <p>気になるスポットを選んで、詳細を見てみましょう。</p>

      <div style={{ display: 'grid', gap: '16px', marginTop: '24px' }}>
        {spots.map((spot) => {
          return (
            <article
              key={spot.id}
              style={{
                border: '1px solid #ddd',
                borderRadius: '12px',
                padding: '16px',
              }}
            >
              <h2>{spot.name}</h2>
              <p>カテゴリ: {spot.category}</p>
              <p>場所: {spot.location}</p>

              <Link href={`/spots/${spot.id}`}>詳細を見る</Link>
            </article>
          );
        })}
      </div>
    </main>
  );
}

ここで何をしているか

このコードでは、3つのスポットを用意しています。

const spots: Spot[] = [
  ...
];

そして、map を使って1件ずつ表示しています。

{spots.map((spot) => {
  return (
    <article key={spot.id}>
      ...
    </article>
  );
})}

最後に、詳細ページへ移動するリンクを作っています。

<Link href={`/spots/${spot.id}`}>詳細を見る</Link>

これにより、スポットごとに違うURLへ移動できます。


5. 詳細ページを作る

次に、/spots/[id] のページを作ります。

作るファイル

app/spots/[id]/page.tsx

フォルダ構成はこうなります。

app
└─ spots
   ├─ page.tsx
   └─ [id]
      └─ page.tsx

[id] は、必ず角かっこ付きで作ります。


app/spots/[id]/page.tsx

Next.js 15 では paramsPromise として受け取る形にしておくと安全です。

type Spot = {
  id: string;
  name: string;
  category: string;
  location: string;
  description: string;
};

const spots: Spot[] = [
  {
    id: '1',
    name: '静かな図書館',
    category: '図書館',
    location: '名古屋駅 徒歩5分',
    description:
      '静かに勉強したいときに使いやすい図書館です。席数も多く、集中しやすい雰囲気があります。',
  },
  {
    id: '2',
    name: 'おしゃれカフェ',
    category: 'カフェ',
    location: '栄駅 徒歩3分',
    description:
      '友人と話したり、少し作業したりするのに使いやすいカフェです。落ち着いた雰囲気があります。',
  },
  {
    id: '3',
    name: '学食の穴場席',
    category: '学食',
    location: '名城大学 2号館',
    description:
      '昼休み以外は比較的空いている席です。短時間の休憩や課題確認に使いやすい場所です。',
  },
];

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

/**
 * 役割: スポット詳細ページを表示する
 * 入力: params - URLに含まれるスポットID
 * 出力: スポット詳細画面
 */
export default async function SpotDetailPage({
  params,
}: SpotDetailPageProps): Promise<JSX.Element> {
  const { id } = await params;

  const spot = spots.find((currentSpot) => {
    return currentSpot.id === id;
  });

  if (spot === undefined) {
    return (
      <main style={{ padding: '32px' }}>
        <h1>スポットが見つかりません</h1>
        <p>指定されたIDのスポットはありません。</p>
      </main>
    );
  }

  return (
    <main style={{ padding: '32px' }}>
      <h1>{spot.name}</h1>
      <p>カテゴリ: {spot.category}</p>
      <p>場所: {spot.location}</p>
      <p>{spot.description}</p>
    </main>
  );
}

ここで何をしているか

URLが /spots/1 のとき、id には '1' が入ります。

const { id } = await params;

その id を使って、表示するスポットを探します。

const spot = spots.find((currentSpot) => {
  return currentSpot.id === id;
});

そして、見つかったスポットだけを画面に表示します。


6. 一覧から詳細へ移動する流れ

ここまで作ると、次の流れができます。

/spots
→ スポット一覧を見る

一覧の「詳細を見る」を押す
→ /spots/1 などへ移動する

/spots/1
→ IDが1のスポット詳細を見る

つまり、

一覧ページで選ぶ
↓
URLにIDが入る
↓
詳細ページでIDを受け取る
↓
該当するデータを表示する

という流れです。


7. URL設計のコツ

URL設計では、次の3つを意識します。

コツ1 短くする

長すぎるURLはわかりにくいです。

よい例です。

/spots
/spots/1

コツ2 意味がわかる単語を使う

spots は「スポット」という意味です。

一覧ページだとわかりやすいです。

よい例です。

/spots
/events
/posts
/users

コツ3 一覧と詳細をセットで考える

一覧と詳細は、セットで考えるとわかりやすいです。

/spots
/spots/1

これは、こういう意味です。

/spots      → スポット全体
/spots/1    → スポットの中の1件

きれいな並びです。


8. よくあるURL設計の例

今後、別のアプリを作るときも、同じ考え方が使えます。

作りたいもの一覧ページ詳細ページ
投稿アプリ/posts/posts/[id]
ユーザー管理/users/users/[id]
商品一覧/products/products/[id]
イベント一覧/events/events/[id]
スポット共有/spots/spots/[id]

この形は、とてもよく使います。


9. 実際に確認しよう

ファイルを作ったら、開発サーバーを起動します。

npm run dev

ブラウザで開きます。

http://localhost:3000/spots

一覧ページが表示されたら、成功です。

次に、一覧の「詳細を見る」を押します。

http://localhost:3000/spots/1

のようなURLに変わり、詳細ページが表示されればOKです。


10. 初心者がよく間違えるところ

間違い1 spots フォルダの場所が違う

正しい場所はここです。

app/spots/page.tsx

components の中に作るわけではありません。


間違い2 [id]id にしてしまう

詳細ページはこれです。

app/spots/[id]/page.tsx

次は間違いです。

app/spots/id/page.tsx

[id] の角かっこには意味があります。


間違い3 URLとフォルダ構成が合っていない

たとえば、/spots/1 を作りたいなら、こうです。

app/spots/[id]/page.tsx

フォルダとURLはつながっています。

迷ったら、フォルダ構成を見直してください。


11. 今回作ったもの

今回作ったのは、次の2つです。

app/spots/page.tsx
app/spots/[id]/page.tsx

これで、次のURLが使えるようになりました。

/spots
/spots/1
/spots/2
/spots/3

12. ここまでのまとめ

URLは、Webアプリの 住所 です。

今回のポイントは、次の4つです。

  • /spots は一覧ページ
  • /spots/[id] は詳細ページ
  • URLを見ただけで画面の内容がわかるようにする
  • Next.jsではフォルダ構成がURLになる

最後に、これだけ覚えてください。

一覧は /spots、詳細は /spots/[id]

これがわかれば、この節は十分です。


練習問題

問題1

スポット一覧ページのURLは何ですか。

問題2

IDが 2 のスポット詳細ページのURLは何ですか。

問題3

/spots/[id][id] には何が入りますか。

問題4

/spots のページを作るファイルはどこですか。


回答

問題1の回答

/spots

問題2の回答

/spots/2

問題3の回答

スポットごとのIDが入ります。

例です。

1
2
3

問題4の回答

app/spots/page.tsx

次に進む前のチェック

次へ進む前に、次の4つを確認してください。

  • /spots が一覧ページだとわかる
  • /spots/[id] が詳細ページだとわかる
  • app/spots/page.tsx を作れる
  • app/spots/[id]/page.tsx を作れる ここまでできればOKです。

次は、フォーム入力の基本に進み、新しいスポットを投稿する画面を作っていきます。

教材トップへ戻る