Svelte入門:SvelteKitでのデータ読み込み -Vol.8-

スポンサーリンク
Svelte入門:SvelteKitでのデータ読み込み -Vol.8- ノウハウ
Svelte入門:SvelteKitでのデータ読み込み -Vol.8-
この記事は約8分で読めます。
よっしー
よっしー

こんにちは。よっしーです(^^)

今日は、SvelteKitでのデータ読み込みについて解説しています。

スポンサーリンク

背景

SvelteKitでのデータ読み込みについて調査する機会がありましたので、その時の内容を備忘として記事に残しました。

SvelteKitでのデータ読み込み

+page.svelte コンポーネント (およびそれに含まれる +layout.svelte コンポーネント) をレンダリングする前に、多くの場合、データを取得する必要があります。これは、ロード関数を定義することによって行われます。

ロード関数の再実行

SvelteKit は、ナビゲーション中に不必要に再実行されることを避けるために、各ロード関数の依存関係を追跡します。 たとえば、次のような 2 つのload関数があるとします。

// src/routes/blog/[slug]/+page.server.js
import * as db from '$lib/server/database';

/** @type {import('./$types').PageServerLoad} */
export async function load({ params }) {
	return {
		post: await db.getPost(params.slug)
	};
}
// src/routes/blog/[slug]/+layout.server.js
import * as db from '$lib/server/database';

/** @type {import('./$types').LayoutServerLoad} */
export async function load() {
	return {
		posts: await db.getPostSummaries()
	};
}

+page.server.jsload関数は、URLのスラッグ(params.slug)が変わると再実行されますが、+layout.server.jsの関数は、データが依然有効なため再実行されません。

親のload関数が再実行された場合、await parent()を呼び出すload関数も再実行されます。

依存関係の追跡はload関数が返された後には適用されません。例えば、ネストされたプロミス内でparams.xにアクセスしても、params.xが変更された際に関数は再実行されません。

検索パラメータは、URLの残りの部分とは独立して追跡されます。event.url.searchParams.get("x")にアクセスするload関数は、xの値が変わると再実行されますが、他のパラメータの変更では再実行されません。

依存関係の追跡を解除する

まれに、依存関係追跡メカニズムから何かを除外したい場合があります。これは、提供されている untrack 関数を使用して行うことができます。

// src/routes/+page.js
/** @type {import('./$types').PageLoad} */
export async function load({ untrack, url }) {
	// Untrack url.pathname so that path changes don't trigger a rerun
	if (untrack(() => url.pathname === '/')) {
		return { message: 'Welcome!' };
	}
}

手動無効化

また、現在のページに適用されるロード関数を再実行するには、 urlに依存するすべてのロード関数を再実行するinvalidate(url)と、 すべてのロード関数を再実行するinvalidateAll()を使用します。サーバのロード関数は、クライアントに秘密が漏れるのを避けるために、 取得した url に自動的に依存することはありません。

fetch(url)またはdepends(url)を呼び出した場合、ロード関数は urlに依存します。urlは[a-z]:で始まるカスタム識別子であることに注意してください:

// src/routes/random-number/+page.js
/** @type {import('./$types').PageLoad} */
export async function load({ fetch, depends }) {
	// load reruns when `invalidate('https://api.example.com/random-number')` is called...
	const response = await fetch('https://api.example.com/random-number');

	// ...or when `invalidate('app:random')` is called
	depends('app:random');

	return {
		number: await response.json()
	};
}
// src/routes/random-number/+page.svelte
<script>
	import { invalidate, invalidateAll } from '$app/navigation';

	/** @type {import('./$types').PageData} */
	export let data;

	function rerunLoadFunction() {
		// any of these will cause the `load` function to rerun
		invalidate('app:random');
		invalidate('https://api.example.com/random-number');
		invalidate(url => url.href.includes('random-number'));
		invalidateAll();
	}
</script>

<p>random number: {data.number}</p>
<button on:click={rerunLoadFunction}>Update random number</button>

ロード関数はいつ再実行されますか?

load関数が再実行される状況は以下の通りです:

  1. 値が変更されたparamsのプロパティを参照している場合
  2. 値が変更されたurlのプロパティ(url.pathnameurl.searchなど)を参照している場合(request.urlのプロパティは追跡されません)
  3. url.searchParams.get(...), url.searchParams.getAll(...), url.searchParams.has(...)を呼び出し、対象のパラメータが変更された場合
  4. await parent()を呼び出し、親のload関数が再実行された場合
  5. 子のload関数がawait parent()を呼び出して再実行中で、親がサーバーサイドのload関数である場合
  6. fetchまたはdependsを通じて特定のURLへの依存関係を宣言し、そのURLがinvalidate(url)でマークされた場合
  7. invalidateAll()によってすべてのアクティブなload関数が強制的に再実行された場合

paramsurlは、リンクのクリック、フォームの操作、gotoの呼び出し、またはredirectによって変更される可能性があります。

load関数の再実行は、対応する+layout.svelteまたは+page.svelte内のdataプロパティを更新しますが、コンポーネントの再作成は行いません。内部状態は保持されます。必要に応じて、afterNavigateコールバック内でリセットを行うか、コンポーネントを{#key ...}ブロックでラップすることができます。

認証への影響

データのロードに関する以下の特徴は、認証チェックに重要な影響を与えます:

  1. レイアウトのload関数は、子ルート間のクライアントサイドナビゲーションなど、すべてのリクエストで実行されるわけではありません。
  2. await parent()が呼び出されない限り、レイアウトとページのload関数は同時に実行されます。レイアウトのload関数がエラーを投げても、ページのload関数は実行されますが、クライアントは返されたデータを受け取りません。

保護されたコードの前に認証チェックを確実に行うための戦略がいくつかあります:

データのウォーターフォールを防ぎ、レイアウトのloadキャッシュを保持するには:

  • フックを使用して、load関数が実行される前に複数のルートを保護する
  • ルート固有の保護には、+page.server.jsload関数内で直接認証ガードを使用する

+layout.server.jsに認証ガードを配置すると、すべての子ページが保護されたコードの前にawait parent()を呼び出す必要があります。すべての子ページがawait parent()から返されるデータに依存しない限り、他のオプションの方がパフォーマンスが高くなります。

おわりに

今日は、 SvelteKitでのデータ読み込みについて解説しました。

よっしー
よっしー

何か質問や相談があれば、コメントをお願いします。また、エンジニア案件の相談にも随時対応していますので、お気軽にお問い合わせください。

それでは、また明日お会いしましょう(^^)

コメント

タイトルとURLをコピーしました