Svelte 5 Runes 実践:$state、$derived、$effect と Svelte 4 からの移行

前端工程

Svelte 5 が注目に値する理由

Svelte 5 は Runes(ルーン) でリアクティビティ・システムを書き直し、「コンパイル時依存追跡」から「明示的・きめ細かい・ファイル横断」のリアクティブ原語へ進化しました。Svelte 4 でクロージャ・非同期・共有モジュール内の let 変数が追跡を失っていた問題を解消し、より小さいランタイムと高い性能をもたらします。

次元 Svelte 4 Svelte 5 (Runes)
状態宣言 let count = 0 let count = $state(0)
派生値 $: doubled = count * 2 let doubled = $derived(count * 2)
副作用 $: console.log(count) $effect(() => console.log(count))
横断共有 stores が必要 .svelte.js で直接 Runes
コンポーネント Props export let let { x } = $props()

コア Runes 一覧

$state:リアクティブ状態を宣言

<script>
  let count = $state(0);
  let user = $state({ name: "Ada", age: 36 });

  function inc() {
    count++;                 // 自動で更新をトリガー
    user.age++;              // 深層プロパティもリアクティブ(プロキシベース)
  }
</script>

<button onclick={inc}>{count} - {user.age}</button>

注意:$state はオブジェクト・配列に 深層プロキシ(deep proxy) を使うため、user.age++ も正確に追跡されます。Svelte 4 の「全体置換」パターンは不要です。

$derived:派生値を宣言

<script>
  let price = $state(100);
  let qty = $state(2);
  let total = $derived(price * qty);     // 依存が変わった時のみ再計算
  let label = $derived.by(() => {
    // 複雑なロジックは .by で関数を包む
    return price > 0 ? `¥${price * qty}` : "無効な価格";
  });
</script>

<p>合計:{total} / {label}</p>

$effect:副作用を宣言

<script>
  let count = $state(0);
  $effect(() => {
    // count を読むことで依存を構築、変化時に再実行
    document.title = `カウント:${count}`;
  });
</script>

$effectブラウザ でのみ実行され、DOM 同期・外部ライブラリ結合・購読クリーンアップに最適。クリーンアップは戻り関数で:

<script>
  let el = $state();
  $effect(() => {
    if (!el) return;
    const obs = new ResizeObserver(() => {/* ... */});
    obs.observe(el);
    return () => obs.disconnect();   // 自動クリーンアップ
  });
</script>

<div bind:this={el}></div>

Props と双方向バインド

$propsexport let を置換

<!-- Child.svelte -->
<script>
  let { title, count = 0, onchange } = $props();
</script>

<h2>{title}: {count}</h2>

$bindable でバインド可能 Props

<!-- Child.svelte -->
<script>
  let { value = $bindable("") } = $props();
</script>

<input bind:value />

<!-- Parent.svelte -->
<script>
  let name = $state("");
</script>

<Child bind:value={name} />
<p>親:{name}</p>

.svelte.js モジュールで Runes を再利用

Svelte 5 の大きな進歩:Runes は .svelte ファイルに留まらない.svelte.js / .svelte.ts でリアクティブ状態を宣言し、真のコンポーネント横断再利用を実現します。

// counter.svelte.js
export const createCounter = () => {
  let count = $state(0);
  const inc = () => count++;
  const double = $derived(count * 2);
  return { get count() { return count; }, get double() { return double; }, inc };
};
<script>
  import { createCounter } from "./counter.svelte.js";
  const c = createCounter();
</script>

<button onclick={c.inc}>{c.count} / {c.double}</button>

テーマ色やコントラスト閾値など複雑な設定を含む状態は、まず JSON フォーマッター で設定オブジェクトを整え、Runes でリアクティブ store に包みます。


ライフサイクルの変化

Svelte 4 Svelte 5 説明
onMount onMount は利用可 マウント時1回
onDestroy $effect のクリーンアップ戻り 破棄クリーンアップを置換
$: 副作用 $effect 統一された副作用入口
beforeUpdate/afterUpdate $effect.pre / $effect より細かい制御
<script>
  import { onMount } from "svelte";
  let ready = $state(false);
  onMount(() => { ready = true; });   // マウント処理はそのまま可
</script>

Svelte 4 からの滑らかな移行

Svelte 5 は大部分の Svelte 4 構文(legacy モード)を支援しますが、段階移行を推奨:

  1. 依存を更新npm i svelte@5、移行ツール npx sv migrate svelte-5
  2. まず状態を移行let x =$state() に。クロージャ・非同期の変数は特に重要。
  3. 次に派生$: y = f(x)let y = $derived(f(x))
  4. 次に副作用$: sideEffect(x)$effect(() => sideEffect(x))
  5. 最後に Propsexport let$props()、双方向が必要なら $bindable
<!-- 移行前 (Svelte 4) -->
<script>
  export let value = 0;
  $: doubled = value * 2;
  $: console.log(doubled);
</script>

<!-- 移行後 (Svelte 5) -->
<script>
  let { value = 0 } = $props();
  let doubled = $derived(value * 2);
  $effect(() => console.log(doubled));
</script>

色やコントラストなどの視覚設定は、色変換色コントラスト ツールでテーマのアクセシビリティ(WCAG)を検証します。


よくある質問 FAQ

Q1:Runes は普通の .js ファイルで使えますか?

使えません。コンパイラが認識できる .svelte.svelte.js.svelte.ts 内のみです。

Q2:$effect 内の非リアクティブ変数の変化はトリガーされますか?

されません。$effect は実行中に読まれたリアクティブ状態のみを追跡します。通常変数の読み取りは依存を作りません。

Q3:Svelte 4 コードは Svelte 5 でそのまま動きますか?

大部分は動きます(legacy 互換)。ただし Runes と旧構文の混在は同一コンポーネント内では不可。コンポーネント単位で段階移行を。

Q4:$derived と $effect の使い分け?

派生する「値」には $derived、 「何かをする」(DOM・購読・ログ)には $effect

Q5:性能向上はどこから?

きめ細かい追跡+コンパイル時最適化で仮想 DOM の diff オーバヘッドを回避し、状態更新が最小の DOM ノードに直接届きます。


推奨ツール

Svelte 5 開発には、以下の ToolsKu ツールが役立ちます:


Svelte 5 の Runes は糖衣構文ではなく、リアクティビティの思考モデルの昇格です。状態は明示的、依存は精密、ファイル横断で再利用可能。$state / $derived / $effect / $props を制覇すれば、次世代 Svelte の鍵を握ったことになります。

ブラウザローカルツールを無料で試す →

#Svelte#Svelte 5#Runes#前端框架#响应式#前端