SvelteKitのload関数の詳細(depends・invalidate・parent)を整理した話
SvelteKitの load 関数を深掘りします。+page.ts と +page.server.ts の使い分け、parent() で親のデータを受け取る方法、depends と invalidate によるリロードなしのデータ再取得を整理します。
load 関数の種類
+page.ts → クライアント・サーバー両方で実行される
+page.server.ts → サーバーのみで実行される(DBアクセス・認証など)
+layout.ts → レイアウト用(クライアント・サーバー両方)
+layout.server.ts → レイアウト用(サーバーのみ)
① +page.ts と +page.server.ts の使い分け
結論:迷ったら +page.server.ts で十分
+page.server.ts はDBアクセス・外部API・認証・環境変数など、ほぼすべての用途をカバーできます。+page.ts が必要になるのは特殊なケースに限られます。
// +page.server.ts を使うべきケース(ほとんどのケース)
export const load = async ({ depends, platform, locals }) => {
// DBアクセス・認証・外部APIすべて対応できる
const posts = await platform!.env.DB
.prepare('SELECT * FROM posts')
.all();
return { posts: posts.results };
};
// +page.ts が必要なケース(特殊)
export const load = async () => {
// localStorageはブラウザにしか存在しないためserver.tsでは使えない
const theme = localStorage.getItem('theme');
return { theme };
};
| 状況 | 結論 |
|---|---|
| DBアクセス・認証・環境変数 | +page.server.ts 一択 |
| 外部APIを叩くだけ | +page.server.ts で十分 |
localStorage など使う |
+page.ts が必要 |
| SSR完全無効化 | +page.ts が必要 |
② parent() で親のデータを受け取る
子の load 関数から親レイアウトのデータを参照できます。
// src/routes/+layout.server.ts
export const load = async ({ locals }) => {
return { user: locals.user };
};
// src/routes/posts/+page.server.ts
export const load = async ({ parent, platform }) => {
const { user } = await parent(); // 親レイアウトの data を受け取る
const posts = await platform!.env.DB
.prepare('SELECT * FROM posts WHERE user_id = ?')
.bind(user.id)
.all();
return { posts: posts.results };
};
③ depends と invalidate でデータを再取得する
depends でload関数に識別子を付けて、invalidate でその識別子を無効化するとload関数が再実行されます。ページリロードなしにデータを最新化できます。
// src/routes/+page.server.ts
export const load: PageServerLoad = async ({ depends, platform }) => {
depends('app:posts'); // この load に識別子を付ける
const result = await platform?.env.DB
.prepare('SELECT * FROM posts')
.all();
return { posts: result?.results ?? [] };
};
<!-- src/routes/+page.svelte -->
<script lang="ts">
import { invalidate } from '$app/navigation';
let { data } = $props();
let refreshing = $state(false);
async function handleRefresh() {
refreshing = true;
await invalidate('app:posts'); // 'app:posts' を持つ load 関数を再実行
refreshing = false;
}
</script>
<button onclick={handleRefresh} disabled={refreshing}>
{refreshing ? '更新中...' : '最新データに更新'}
</button>
<ul>
{#each data.posts as post}
<li>{post.title}</li>
{/each}
</ul>
ポイント: actions + use:enhance の組み合わせではSvelteKitが自動的にloadを再実行するため invalidate は不要です。fetch で直接APIを叩くような場面で invalidate が活きます。
④ invalidateAll で全データを再取得する
全てのload関数を再実行したいときは invalidateAll を使います。
<script lang="ts">
import { invalidateAll } from '$app/navigation';
async function handleRefresh() {
await invalidateAll(); // 全 load 関数を再実行
}
</script>
<button onclick={handleRefresh}>最新データに更新</button>
まとめ
| 内容 | |
|---|---|
+page.server.ts |
DBや認証が必要なときはこちら。ほとんどのケースで十分 |
+page.ts |
localStorage など使う特殊なケースのみ |
parent() |
親レイアウトのloadデータを子で使う |
depends('識別子') |
load関数に再実行トリガーの識別子を付ける |
invalidate('識別子') |
特定のloadだけ再実行する |
invalidateAll() |
全てのloadを再実行する |