Svelte 5のSvelteMap・SvelteSetでリアクティブなデータ構造を使った話
Svelte 5では $state でオブジェクトや配列をリアクティブにできますが、Map や Set は .set() や .add() などの操作では画面が更新されません。これを解決するのが svelte/reactivity のクラスです。
なぜ普通のMapやSetではダメなのか
$state は参照の変化を追跡しますが、Map や Set の中身の変化は追跡できません。
<script lang="ts">
// ❌ 普通のMapは中身が変わっても画面が更新されない
let map = $state(new Map());
map.set('key', 'value'); // 参照は変わらないので再レンダリングされない
</script>
svelte/reactivity が提供するクラス
| クラス | 対応する標準クラス |
|---|---|
SvelteMap |
Map |
SvelteSet |
Set |
SvelteDate |
Date |
SvelteURL |
URL |
標準クラスと同じAPIで使えます。
SvelteMap の使い方
キーと値のペアを管理します。.set() や .delete() のたびに画面が自動更新されます。
<script lang="ts">
import { SvelteMap } from 'svelte/reactivity';
let scores = new SvelteMap<string, number>([
['Alice', 80],
['Bob', 70],
]);
</script>
<ul>
{#each scores as [name, score]}
<li>{name}: {score}点
<button onclick={() => scores.set(name, score + 10)}>+10</button>
<button onclick={() => scores.delete(name)}>削除</button>
</li>
{/each}
</ul>
<button onclick={() => scores.set('Carol', 60)}>Carolを追加</button>
SvelteSet の使い方
重複した値を自動で除外するデータ構造です。タグ管理などに便利です。
<script lang="ts">
import { SvelteSet } from 'svelte/reactivity';
let tags = new SvelteSet<string>(['svelte', 'cloudflare']);
let newTag = $state('');
</script>
<ul>
{#each tags as tag}
<li>{tag}
<button onclick={() => tags.delete(tag)}>削除</button>
</li>
{/each}
</ul>
<input bind:value={newTag} placeholder="タグを入力" />
<button onclick={() => { tags.add(newTag); newTag = ''; }}>追加</button>
<p>※重複したタグは追加されません</p>
通常の配列・オブジェクトとの使い分け
| データ | 使うもの |
|---|---|
| 配列(順序あり・重複あり) | $state([]) |
| オブジェクト | $state({}) |
| キーと値のペア | SvelteMap |
| 重複なしのリスト | SvelteSet |
| 日付 | SvelteDate |
| URL | SvelteURL |
まとめ
$state(new Map())では.set()などの操作で画面が更新されないSvelteMap/SvelteSetを使うと中身の変化もリアクティブに追跡できる- 標準の
Map/Setと同じAPIで使えるので移行も簡単