何をするか?
Svelte 5 のコンポーネントで使用する状態変数は $state
ルーンを使って定義できますが、ページをリロードするとその値はリセットされてしまいます。
この記事では、$state
ルーンで定義した状態変数の値を localStorage
や sessionStorage
と同期させる方法を紹介します。
localStorage
と同期させた場合は、ブラウザを開き直したときにも以前の状態を復帰できます。
sessionStorage
と同期させた場合は、ブラウザのタブを開いている間だけ状態を保持できます。
$state
ルーンを使って状態変数を共有する方法は、下記の記事を参照してください。
実装例

ここでは、サインイン状態を管理する AuthState
クラスを作成し、その userName
プロパティ(状態変数)を localStorage
に保存する例を示します。
サインイン状態を示す signedIn
プロパティも用意していますが、こちらは $derived
ルーンで定義されており、userName
プロパティの値に応じて自動的に値が決まるようになっています(userName
がセットされているときに true
になります)。
import { onMount } from 'svelte';
const STORAGE_KEY = 'userName';
// 複数のコンポーネントで状態を共有するため、リアクティブな変数をグローバルに定義します
let userName = $state('');
let signedIn = $derived(!!userName);
export class AuthState {
/** サインインしているユーザー名を参照するためのプロパティ (reactive) */
get userName(): string {
return userName;
}
/** サインインしているかどうかを示すプロパティ (reactive) */
get signedIn(): boolean {
return signedIn;
}
constructor() {
// ページが読み込まれたときに localStorage の値で状態変数を初期化します
// (このコードはコンポーネントの初期化中に呼び出す必要があります)
onMount(() => {
userName = localStorage.getItem(STORAGE_KEY) || '';
});
}
signIn(): void {
// 実際には正しいユーザー情報やトークンを取得して保存します
userName = 'Maku';
localStorage.setItem(STORAGE_KEY, userName);
}
signOut(): void {
userName = '';
localStorage.removeItem(STORAGE_KEY);
}
}
AuthState
クラスのコンストラクターでは、Svelte のライフサイクルフックである onMount()
関数を使って、ページが読み込まれたときに localStorage
から userName
の値を取得しています。
これにより、ページをリロードしたときに以前の状態を復元できます。
Svelte の仕組み上、onMount
関数はコンポーネントの初期化中にしか呼び出せないため、new AuthState()
というインスタンス化コードはコンポーネント側に記述する必要があります(後述)。
signIn()
および signOut()
メソッドは、userName
状態変数の値を変更すると同時に localStorage
にもその値を保存することで、次回のページ読み込みに備えています。
ここでは、主な状態変数としてユーザー名だけを扱っていますが、実際のアプリケーションでは、サインイン時に取得したアクセストークンなどの情報を保存することが一般的です。
次に、この AuthState
クラスを利用するコンポーネントを作成します。
サインイン/アウトのボタンを持つサイトヘッダーが典型的な例です。
<script lang="ts">
import { AuthState } from '$lib/auth-state.svelte';
const authState = new AuthState(); // 内部で onMount フックがセットされる
</script>
<header>
<h1>My Site</h1>
{#if authState.signedIn}
<div>Welcome, {authState.userName}!</div>
<button onclick={() => authState.signOut()}>Sign out</button>
{:else}
<button onclick={() => authState.signIn()}>Sign in</button>
{/if}
</header>
<style>
* {
margin: 0;
}
header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.5rem 1rem;
background-color: #f0f0f0;
}
button {
font-size: 1rem;
padding: 0.5rem 1rem;
border: none;
border-radius: 0.25rem;
background-color: #007bff;
color: white;
cursor: pointer;
}
button:hover {
background: #0065d8;
}
</style>
このコンポーネントを +layout.svelte
に組み込むことで、全ページにサイトヘッダーを表示できます。
<script lang="ts">
import SiteHeader from '$lib/components/SiteHeader.svelte';
</script>
<SiteHeader />
<slot />
できたー ٩(๑❛ᴗ❛๑)۶ わーぃ