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

はじめに
この節では、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 では params を Promise として受け取る形にしておくと安全です。
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です。
次は、フォーム入力の基本に進み、新しいスポットを投稿する画面を作っていきます。
