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

スポンサーリンク
Svelte入門:SvelteKitでのデータ読み込み -Vol.7- 用語解説
Svelte入門:SvelteKitでのデータ読み込み -Vol.7-
この記事は約6分で読めます。
よっしー
よっしー

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

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

スポンサーリンク

背景

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

SvelteKitでのデータ読み込み

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

リダイレクト

ユーザーをリダイレクトするには、@sveltejs/kit のリダイレクト ヘルパーを使用して、3xx ステータス コードとともにリダイレクト先の場所を指定します。error(…) と同様に、redirect(…) を呼び出すと例外がスローされるため、ヘルパー関数内から実行を簡単に停止できます。

// src/routes/user/+layout.server.js
import { redirect } from '@sveltejs/kit';

/** @type {import('./$types').LayoutServerLoad} */
export function load({ locals }) {
	if (!locals.user) {
		redirect(307, '/login');
	}
}

リダイレクトによってすぐに catch ステートメントがトリガーされるため、try {…} ブロック内で redirect() を使用しないでください。

ブラウザーでは、$app.navigation から goto を使用して、ロード関数の外側にプログラム的に移動することもできます。

ストリーミング

サーバー負荷を使用する場合、Promise は解決時にブラウザにストリーミングされます。これは、すべてのデータが利用可能になる前にページのレンダリングを開始できるため、低速で必須ではないデータがある場合に便利です。

// src/routes/blog/[slug]/+page.server.js
/** @type {import('./$types').PageServerLoad} */
export async function load({ params }) {
	return {
		// make sure the `await` happens at the end, otherwise we
		// can't start loading comments until we've loaded the post
		comments: loadComments(params.slug),
		post: await loadPost(params.slug)
	};
}

これは、次のようなスケルトンの読み込み状態を作成するのに役立ちます。

src/routes/blog/[slug]/+page.svelte
<script>
	/** @type {import('./$types').PageData} */
	export let data;
</script>

<h1>{data.post.title}</h1>
<div>{@html data.post.content}</div>

{#await data.comments}
	Loading comments...
{:then comments}
	{#each comments as comment}
		<p>{comment.content}</p>
	{/each}
{:catch error}
	<p>error loading comments: {error.message}</p>
{/await}

データをストリーミングする場合、Promise の拒否を正しく処理するように注意してください。具体的には、遅延ロードされた Promise がレンダリングの開始前 (その時点でキャッチされます) に失敗し、何らかの方法でエラーを処理していない場合、サーバーは「未処理の Promise 拒否」エラーでクラッシュする可能性があります。SvelteKit の fetch を load 関数で直接使用すると、SvelteKit がこのケースを処理します。他の Promise の場合は、処理済みとしてマークするために、Promise に noop-catch を添付するだけで十分です。

// src/routes/+page.server.js
/** @type {import('./$types').PageServerLoad} */
export function load({ fetch }) {
	const ok_manual = Promise.reject();
	ok_manual.catch(() => {});

	return {
		ok_manual,
		ok_fetch: fetch('/fetch/that/could/fail'),
		dangerous_unhandled: Promise.reject()
	};
}

AWS Lambda や Firebase などのストリーミングをサポートしていないプラットフォームでは、応答はバッファリングされます。つまり、すべての Promise が解決された場合にのみページがレンダリングされます。プロキシ (NGINX など) を使用している場合は、プロキシ サーバーからの応答がバッファリングされないようにしてください。

ストリーミング データは、JavaScript が有効になっている場合にのみ機能します。ページがサーバーでレンダリングされる場合は、ユニバーサル ロード関数から promise を返すことは避けてください。これは、promise がストリーミングされないためです。代わりに、関数がブラウザーで再実行されると、promise が再作成されます。

応答のストリーミングが開始されると、応答のヘッダーとステータス コードを変更することはできないため、ストリーミングされた Promise 内で Headers を設定したり、リダイレクトをスローしたりすることはできません。

並列ロード

ページをレンダリング (またはページに移動) する際、SvelteKit はすべてのロード関数を同時に実行し、リクエストのウォーターフォールを回避します。クライアント側のナビゲーション中、複数のサーバー ロード関数を呼び出した結果が 1 つの応答にグループ化されます。すべてのロード関数が返されると、ページがレンダリングされます。

おわりに

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

よっしー
よっしー

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

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

コメント

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