Svelte 5のSvelteMap・SvelteSetでリアクティブなデータ構造を使った話

Svelte 5では $state でオブジェクトや配列をリアクティブにできますが、MapSet.set().add() などの操作では画面が更新されません。これを解決するのが svelte/reactivity のクラスです。


なぜ普通のMapやSetではダメなのか

$state は参照の変化を追跡しますが、MapSet中身の変化は追跡できません。

<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で使えるので移行も簡単
← トップページに戻る