effect は、state が更新されたときに実行される関数で、サードパーティのライブラリを呼び出したり、`` 要素を描画したり、ネットワークリクエストを行ったりするために使用できます。effect はブラウザ上でのみ実行され、サーバーサイドレンダリング中には実行されません。 一般的に、effect 内で state を更新するべきではありません。なぜなら、コードが複雑になり、無限ループに陥ることがあるからです。もしそのようなことをしているなら、[`$effect` を使うべきでないとき](#When-not-to-use-$effect) のセクションを参照して、別のアプローチについて学んでください。 `$effect` rune を使って effect を作成します (デモ: ```svelte ``` Svelte が effect 関数を実行するとき、どの state (および derived state) がアクセスされたかを追跡し ([`untrack`](svelte#untrack) の内側でアクセスされた場合を除く)、その state が後で変更されたときにその effect 関数を再実行します。 > [!NOTE] なぜ `$effect` が再実行されるのか、または再実行されないのかを理解するのが難しい場合は、[依存関係を理解する](#Understanding-dependencies) を参照してください。Svelte 4 の `$:` ブロックとは異なる方法で effect がトリガーされます。 ### ライフサイクルを理解する effect は、コンポーネントが DOM にマウントされた後に実行されます。また、state が変更された後には [マイクロタスク](https://developer.mozilla.org/ja/docs/Web/API/HTML_DOM_API/Microtask_guide) で実行されます。再実行はバッチ処理され (つまり、同じ瞬間に `color` と `size` を変更しても、2つの別々の実行は発生しません)、DOM 更新が適用された後に実行されます。 `$effect` は、親の effect の実行中に呼び出される限りは、コンポーネントのトップレベルだけでなく、どこでも使用できます。 > [!NOTE] Svelte はテンプレート内のロジックや式を表現するために内部的に effect を使用しています — これによって `name` の変更時に `

hello {name}!

` を更新しているのです。 An effect can return a _teardown function_ which will run immediately before the effect re-runs: ```svelte

{count}

``` teardown 関数は、effect が破棄されるときにも実行されます。これは、親が破棄されたとき (例えば、コンポーネントがアンマウントされたとき) や親 effect が再実行されたときに発生します。 ### 依存関係を理解する `$effect` は、関数本体内で _同期的に_ 読み取られるリアクティブな値 (`$state`, `$derived`, `$props`) を (間接的なもの、関数呼び出し経由も含めて) 自動的に検出し、依存関係(dependencies)として登録します。これらの依存関係が変更されると、`$effect` は再実行をスケジュールします。 もし `$state` や `$derived` が `$effect` 内で直接使用されている場合 (例えば、[リアクティブなclass](https://svelte.jp/docs/svelte/$state#Classes)の作成中など)、それらの値は依存関係として扱われません。 非同期的に読み取られる値 (例えば、`await` の後や `setTimeout` 内) は追跡されません。この例では、`color` が変更されると canvas が再描画されますが、`size` が変更されても再描画されません (デモ。 ```ts // @filename: index.ts declare let canvas: { width: number; height: number; getContext(type: '2d', options?: CanvasRenderingContext2DSettings): CanvasRenderingContext2D; }; declare let color: string; declare let size: number; // ---cut--- $effect(() => { const context = canvas.getContext('2d'); context.clearRect(0, 0, canvas.width, canvas.height); // これは `color` が変更されるたびに再実行されます... context.fillStyle = color; setTimeout(() => { // ...しかしこれは `size` が変更されても再実行されません context.fillRect(0, 0, size, size); }, 0); }); ``` effect は、読み取るオブジェクトそのものが変更された場合にのみ再実行され、その中のプロパティが変更された場合には再実行されません。(オブジェクト内部の変更を開発時に観察したい場合は、[`$inspect`]($inspect) を使用できます。) ```svelte

{state.value} doubled is {derived.value}

``` effect は、前回実行されたときに読み取られた値のみに依存します。これは、条件付きコードを持つ effect にとって興味深い含意があります。 例えば、以下のコードスニペットで `condition` が `true` の場合、`if` ブロック内のコードが実行され、`color` が評価されます。これはつまり、`condition` または `color` の変更が effect の再実行を引き起こすということです。 一方で、`condition` が `false` の場合、`color` は評価されず、 effect は `condition` が変更されたときに _のみ_ 再実行されます。 ```ts // @filename: ambient.d.ts declare module 'canvas-confetti' { interface ConfettiOptions { colors: string[]; } function confetti(opts?: ConfettiOptions): void; export default confetti; } // @filename: index.js // ---cut--- import confetti from 'canvas-confetti'; let condition = $state(true); let color = $state('#ff3e00'); $effect(() => { if (condition) { confetti({ colors: [color] }); } else { confetti(); } }); ``` ## `$effect.pre` 稀なケースでは、DOM 更新の _前に_ コードを実行する必要がある場合があります。そのためには `$effect.pre` rune を使用できます: ```svelte
{#each messages as message}

{message}

{/each}
``` タイミングを除けば、`$effect.pre` は `$effect` とまったく同じように機能します。 ## `$effect.tracking` The `$effect.tracking` rune is an advanced feature that tells you whether or not the code is running inside a tracking context, such as an effect or inside your template: ```svelte

in template: {$effect.tracking()}

``` これは、[`createSubscriber`](/docs/svelte/svelte-reactivity#createSubscriber) のような抽象化を実装するために使用されます。これにより、リアクティブな値を更新するリスナーが作成されますが、それらの値が追跡されている場合に _のみ_ 実行されます (例えば、イベントハンドラー内で読み取られる場合は除きます)。 ## `$effect.pending` When using [`await`](await-expressions) in components, the `$effect.pending()` rune tells you how many promises are pending in the current [boundary](svelte-boundary), not including child boundaries: ```svelte

{a} + {b} = {await add(a, b)}

{#if $effect.pending()}

pending promises: {$effect.pending()}

{/if} ``` ## `$effect.root` `$effect.root` rune は高度な機能で、自動クリーンアップされない非トラッキングスコープ (non-tracked scope) を作成します。これは、手動で制御したいネストされた effect に便利です。また、この rune は、コンポーネント初期化フェーズの外部で effect を作成することも可能にします。 ```js const destroy = $effect.root(() => { $effect(() => { // setup }); return () => { // cleanup }; }); // later... destroy(); ``` ## `$effect` を使うべきでないとき 一般的に、`$effect` は脱出口 (エスケープハッチ) のようなものと考えるのが最善です。たとえば、アナリティクス や直接的な DOM 操作などに便利ですが、頻繁に使用するツールではありません。特に、state を同期するために使用するのは避けてください。このように使用するのではなく... ```svelte ``` ...このようにしてください: ```svelte ``` > [!NOTE] `count * 2` のような単純な式よりも複雑なものの場合は、`$derived.by` を使用することもできます。 (例えば楽観的 UI を作るために) derived な値に再代入するために effect を使用しているなら、Svelte 5.25 からは [derived を直接オーバーライドできる]($derived#Overriding-derived-values) ようになったことにご留意ください。 You might be tempted to do something convoluted with effects to link one value to another. The following example shows two inputs for "money spent" and "money left" that are connected to each other. If you update one, the other should update accordingly. Instead of using effects for this... ```svelte ``` ...use `oninput` callbacks or — better still — [function bindings](bind#Function-bindings) where possible: ```svelte ``` どうしても effect 内で `$state` を更新する必要があり、同じ `$state` を読み書きすることで無限ループに陥った場合は、[untrack](svelte#untrack) を使用してください。