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 と双方向バインド
$props が export 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 モード)を支援しますが、段階移行を推奨:
- 依存を更新:
npm i svelte@5、移行ツールnpx sv migrate svelte-5。 - まず状態を移行:
let x =を$state()に。クロージャ・非同期の変数は特に重要。 - 次に派生:
$: y = f(x)→let y = $derived(f(x))。 - 次に副作用:
$: sideEffect(x)→$effect(() => sideEffect(x))。 - 最後に Props:
export 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 ツールが役立ちます:
- JSON フォーマッター — コンポーネント設定と状態スナップショットの整理
- 色変換 — HEX/RGB/HSL 相互変換、テーマ状態と併用
- 色コントラスト — テーマ色の WCAG アクセシビリティ検証
Svelte 5 の Runes は糖衣構文ではなく、リアクティビティの思考モデルの昇格です。状態は明示的、依存は精密、ファイル横断で再利用可能。
$state / $derived / $effect / $propsを制覇すれば、次世代 Svelte の鍵を握ったことになります。
ブラウザローカルツールを無料で試す →