SvelteKitで記事一覧・詳細ページを作った話
SvelteKitのチュートリアルを一通り終えた後、実際に手を動かして定着させるために記事一覧・詳細ページを作りました。 この記事では、そこで学んだ動的ルーティングとload関数の基礎をまとめます。
このシリーズの記事
- SvelteKitで記事一覧・詳細ページを作った話(この記事)
- SvelteKitでTODOアプリを作った話
- SvelteKitで認証・セッション管理を実装した話
- SvelteKitをCloudflare Pagesにデプロイした話
作ったもの
/:記事タイトルの一覧が並ぶページ/posts/1のように記事IDをURLに含む詳細ページ- 存在しないIDにアクセスすると404エラーページ
ファイル構成
src/routes/
+layout.svelte # 全ページ共通レイアウト
+page.svelte # 記事一覧ページ
posts/
[id]/
+page.svelte # 記事詳細ページ(UI)
+page.ts # 記事詳細のload関数
動的ルーティング:[id] フォルダ
/posts/1 や /posts/2 のようにURLにパラメータが入るページは、フォルダ名を [id] にするだけで対応できます。
mkdir -p src/routes/posts/[id]
フォルダ名の [id] 部分がそのままパラメータ名になります。[slug] や [userId] のように自由に命名できます。
一覧ページ:+page.svelte
まず一覧ページにデータを直書きして、リンクを並べます。
<!-- src/routes/+page.svelte -->
<script lang="ts">
const posts = [
{ id: 1, title: 'SvelteKitとは', body: 'SvelteKitはフルスタックフレームワークです。' },
{ id: 2, title: 'ルーティング入門', body: 'ファイルベースのルーティングを使います。' },
{ id: 3, title: 'load関数の使い方', body: 'データ取得はload関数で行います。' },
];
</script>
<h1>記事一覧</h1>
<ul>
{#each posts as post}
<li>
<a href="/posts/{post.id}">{post.title}</a>
</li>
{/each}
</ul>
詳細ページ:load関数でデータを渡す
詳細ページはUIとデータ取得を分離します。+page.ts にload関数を書き、+page.svelte で受け取る構成です。
+page.ts(load関数)
// src/routes/posts/[id]/+page.ts
import { error } from "@sveltejs/kit";
import type { PageLoad } from "./$types";
const posts = [
{
id: 1,
title: "SvelteKitとは",
body: "SvelteKitはフルスタックフレームワークです。",
},
{
id: 2,
title: "ルーティング入門",
body: "ファイルベースのルーティングを使います。",
},
{
id: 3,
title: "load関数の使い方",
body: "データ取得はload関数で行います。",
},
];
export const load: PageLoad = ({ params }) => {
const post = posts.find((p) => p.id === Number(params.id));
if (!post) error(404, "記事が見つかりません");
return { post };
};
params.id でURLのパラメータを取得できます。記事が見つからない場合は error() でそのまま404ページに飛ばします。
+page.svelte(UI)
<!-- src/routes/posts/[id]/+page.svelte -->
<script lang="ts">
let { data } = $props();
</script>
<h1>{data.post.title}</h1>
<p>{data.post.body}</p>
<a href="/">← 一覧に戻る</a>
$props() で受け取った data の中に、load関数が返したオブジェクトがそのまま入っています。
PageLoad 型をつける理由
チュートリアルでは型なしで書くことが多いですが、実際のプロジェクトでは PageLoad を付けるのが推奨です。
// 型なし(動くが補完が効かない)
export function load({ params }) {
return { post };
}
// 型あり(推奨)
export const load: PageLoad = ({ params }) => {
return { post };
};
PageLoad はSvelteKitがファイル構成を見て ./$types に自動生成する型です。これを付けることで、params に何が入るか・return した値が data としてどう渡るかをTypeScriptが把握し、誤った使い方をエディタが検出してくれます。
まとめ
| 概念 | 内容 |
|---|---|
[id] フォルダ |
URLのパラメータに対応する動的ルート |
params.id |
URLのパラメータを取得 |
+page.ts の load 関数 |
ページに渡すデータを返す |
error(404, ...) |
エラーページに飛ばす |
let { data } = $props() |
load関数の戻り値を受け取る |
PageLoad 型 |
TypeScriptで型安全にする |
load関数をページのUIと分離することで、データの取得と表示の責務がはっきりします。次はこのデータを $lib に切り出して共通化するところを試してみます。