こんにちは。よっしーです(^^)
今日は、SvelteKitでのstate管理について解説しています。
背景
SvelteKitでのstate管理について調査する機会がありましたので、その時の内容を備忘として記事に残しました。
SvelteKitでのstate管理について
クライアントのみのアプリの構築に慣れている場合、サーバーとクライアントにまたがるアプリでの状態(state)管理は困難に思えるかもしれません。このセクションでは、よくある落とし穴を回避するためのヒントを紹介します。
コンポーネントとページの状態は保存されます
アプリケーション内を移動すると、SvelteKit は既存のレイアウトとページ コンポーネントを再利用します。たとえば、次のようなルートがある場合…
// src/routes/blog/[slug]/+page.svelte
<script>
/** @type {import('./$types').PageData} */
export let data;
// THIS CODE IS BUGGY!
const wordCount = data.content.split(' ').length;
const estimatedReadingTime = wordCount / 250;
</script>
<header>
<h1>{data.title}</h1>
<p>Reading time: {Math.round(estimatedReadingTime)} minutes</p>
</header>
<div>{@html data.content}</div>
解説
上記のコードは Svelte を使用したブログ記事ページのコンポーネントを定義していますが、いくつかの問題点があります。コードを解説し、その後で問題点と改善案を提示します。
コードの説明:
export let data;
– SvelteKit のページコンポーネントで、ロード関数から渡されたデータを受け取ります。const wordCount = data.content.split(' ').length;
– 記事の内容を空白で分割し、単語数を数えようとしています。const estimatedReadingTime = wordCount / 250;
– 平均的な読書速度(1分間に250単語)を基に、推定読書時間を計算しています。- テンプレート部分では、記事のタイトル、推定読書時間、そして記事の内容を表示しています。
問題点と改善案:
…そのため、/blog/my-short-post
から/blog/my-long-post
に移動しても、レイアウト、ページ、およびその中の他のコンポーネントが破棄されて再作成されることはありません。代わりに、data
プロップ(そして拡張してdata.title
とdata.content
)が更新されます(他のSvelteコンポーネントと同様に)。そして、コードが再実行されないため、onMount
やonDestroy
のようなライフサイクルメソッドは再実行されず、estimatedReadingTime
も再計算されません。
代わりに、値をリアクティブにする必要があります:
// src/routes/blog/[slug]/+page.svelte
<script>
/** @type {import('./$types').PageData} */
export let data;
$: wordCount = data.content.split(' ').length;
$: estimatedReadingTime = wordCount / 250;
</script>
ナビゲーション後に onMount と onDestroy のコードを再度実行する必要がある場合は、それぞれ afterNavigate と beforeNavigate を使用できます。
このようにコンポーネントを再利用することで、サイドバーのスクロール状態などが保持され、変更される値の間で簡単にアニメーションを付けることができます。ナビゲーション時にコンポーネントを完全に破棄して再マウントする必要がある場合は、次のパターンを使用できます:
{#key $page.url.pathname}
<BlogPost title={data.title} content={data.title} />
{/key}
おわりに
今日は、 SvelteKitでのstate管理について解説しました。
何か質問や相談があれば、コメントをお願いします。また、エンジニア案件の相談にも随時対応していますので、お気軽にお問い合わせください。
それでは、また明日お会いしましょう(^^)
コメント