7
4

SvelteKit のデータローディング load() 周りのうごきを整理するメモ

Last updated at Posted at 2024-07-22

Screenshot 2024-07-22 at 13.33.14.png

Next.js や Nuxt などのSSR対応フレームワークと同様に、SvelteKit もデータの読み込みのための標準の方法を備えています(SSRのハイドレーションをうまくやるためですね)。

SvelteKit ではこのデータローディングの面でもファイルベースのルーティングを用いていて、各ルートの +page.ts, +layout.ts, +page.server.ts, +layout.server.ts のファイルで、データ取得処理を load() 関数として記述することで、ページコンポーネントやレイアウトコンポーネントにデータを供給できます。SSRのための裏方の作業も勝手にやってくれます。

...というのは、皆さんご存知だとして、ここではもう少し細かい話を整理してみます。

公式ドキュメントは以下にあります

+page.ts+page.server.ts の使い分け

についても、一応触れておきます。

Universal vs server: https://kit.svelte.dev/docs/load#universal-vs-server

  • +page.ts+layout.ts には、ユニバーサルな(=サーバ上でもブラウザ上でも実行できる)データ取得処理を記述します。サーバサイドレンダリング時にはサーバで実行され、ブラウザでのページ遷移時などにはブラウザで実行されます。ユニバーサルな処理はこちらに書くべきです。
  • 一方で +page.server.ts+layout.server.ts は常にサーバ上で実行されます。必ずサーバ上で実行しなければならない処理はこちらに記述します。

provided fetch function を使え

Load関数内では、ネイティブの fetch 関数ではなく、SvelteKit が提供する fetch 関数を使います。 load 関数の引数として渡される fetch 関数を受け取って使います。

+page.ts
export const load: PageLoad = async ({ fetch, params }) => {
	const res = await fetch(`/api/items/${params.id}`);
	const item = await res.json();
	return { item };
};

この特別な fetch には SSR を支援するための工夫がなされています:

  • SvelteKitが受けた Cookie と Authorization ヘッダが fetch 先にも自動で転送される(APIに認証情報を渡すのに便利)
  • URLとして相対URLが使える(ユニバーサルな記述をするのに便利)
  • SSRのハイドレーションにおいて、サーバでfetchした内容がHTMLに焼き込まれて、ブラウザ側でも同じ内容が取得される。これにより無駄なリクエストがサーバとクライアントの両方で走らない。
  • などなど。詳しくは https://kit.svelte.dev/docs/load#making-fetch-requests

load 関数の再実行

Load関数は、URLの変化などに応じて、必要なものだけが自動で再実行されます(SvelteKit がこれらの変化を追跡する機能を備えています)。詳細はドキュメントを参照してください。 https://kit.svelte.dev/docs/load#rerunning-load-functions

手動での invalidation

しかしながら、Load関数が取得した内容を、ページ遷移などをせずに再読み込みさせたい場面もあります。その場合は invalidate 関数が使えます。 https://kit.svelte.dev/docs/load#rerunning-load-functions-manual-invalidation

fetch したURLを指定して invalidate するのが基本的な使い方です。そのURLに依存しているLoad関数がすべて再実行されます。

    invalidate('https://api.example.com/random-number');
    invalidate('app:random');  // カスタムの依存関係も作れる → depends を参照
    invalidate((url) => url.href.includes('random-number'));
    invalidateAll();

各Load関数間の data の流れ

様々な load 関数がどのような流れで働くかは、少し分りづらいところがあるように思います。

各 load 関数の間での data の流れについて、いくつかの要点を整理してみます:

  • +layout.server.ts, +layout.ts で取得したデータは、その配下(子レイアウトや子ページ)にあるすべての +layout.svelte+page.svelte でも参照できます。この振る舞いは重要かもしれません。
    • プロパティ名が衝突した場合は下位の load 関数によるものが優先される、とされています。勝手にオブジェクトがマージされたりはしません。注意。
  • +layout.server.ts で取得したデータは対応する +layout.ts で参照できます。同様に、+page.server.ts で取得したデータは対応する +page.ts で参照できます。
  • parent() — Load関数で await parent() すると、親の +layout.ts+layout.server.ts の data を待機して取得できます。ただしデータ取得の並列性を阻害するため、極力使用を避けるように注意されています。
  • 認証ガードなどの目的で、すべてのリクエストをフックする hooks.server.ts を使う場合は、hooks.server.ts で得られたデータを +(layout|page).server.ts にも送りたい場合は、リクエストローカルな event.locals を介して送ることができます。

適当な図にすると、以下のようになるでしょうか:

Screenshot 2024-07-22 at 13.33.14.png

7
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
4