$derived
derived state は $derived
rune を使用して宣言します:
日本語翻訳 TIPS:「derive」は「引き出す」「派生する」「由来する」などの意。「derived state」は、他の state を元に計算される state を意味します。
<script>
let count = $state(0);
let doubled = $derived(count * 2);
</script>
<button onclick={() => count++}>
{doubled}
</button>
<p>{count} doubled is {doubled}</p>
$derived(...)
内の式は副作用(side-effects)がないものでなければなりません。Svelte は derived の式の中での state の変更 (例: count++
) を許可しません。
$state
と同様に、class のフィールドを $derived
としてマークすることができます。
Svelte コンポーネント内のコードは作成時に一度だけ実行されます。
$derived
rune がない場合、count
が変化してもdoubled
は元の値を維持します。
$derived.by
短い式に収まらない複雑な derived を作成する必要がある場合があります。その場合は、引数として関数を受け取る $derived.by
を使用できます。
<script>
let numbers = $state([1, 2, 3]);
let total = $derived.by(() => {
let total = 0;
for (const n of numbers) {
total += n;
}
return total;
});
</script>
<button onclick={() => numbers.push(numbers.length + 1)}>
{numbers.join(' + ')} = {total}
</button>
本質的に、$derived(expression)
は $derived.by(() => expression)
と同等です。
依存関係を理解する
$derived
式 (または $derived.by
の関数本体) 内で同期的に読み取られるものはすべて、derived state の 依存関係(dependency) と見なされます。その state が変更されると、derived は dirty としてマークされ、次回読み取られる際に再計算されます。
state の一部を依存関係として扱わないようにするには、untrack
を使用します。
Overriding derived values
Derived expressions are recalculated when their dependencies change, but you can temporarily override their values by reassigning them (unless they are declared with const
). This can be useful for things like optimistic UI, where a value is derived from the ‘source of truth’ (such as data from your server) but you’d like to show immediate feedback to the user:
<script>
let { post, like } = $props();
let likes = $derived(post.likes);
async function onclick() {
// increment the `likes` count immediately...
likes += 1;
// and tell the server, which will eventually update `post`
try {
await like();
} catch {
// failed! roll back the change
likes -= 1;
}
}
</script>
<button {onclick}>🧡 {likes}</button>
Prior to Svelte 5.25, deriveds were read-only.
Deriveds and reactivity
Unlike $state
, which converts objects and arrays to deeply reactive proxies, $derived
values are left as-is. For example, in a case like this...
let items = $state([...]);
let index = $state(0);
let selected = $derived(items[index]);
...you can change (or bind:
to) properties of selected
and it will affect the underlying items
array. If items
was not deeply reactive, mutating selected
would have no effect.
更新の伝搬
Svelte は push-pull reactivity と呼ばれる仕組みを使用しています — state が更新されると、それに依存するすべてのもの (直接的または間接的であるかを問わず) に即座に変更が通知されますが (‘push’)、derived の値は実際に読み取られるまで再評価されません (‘pull’)。
derived の新しい値が以前の値と参照的に同一である場合、下流の更新はスキップされます。つまり、large
が変更されたときのみ、ボタン内のテキストが更新され、count
が変更されても更新されません (たとえ large
が count
に依存していたとしても):
<script>
let count = $state(0);
let large = $derived(count > 10);
</script>
<button onclick={() => count++}>
{large}
</button>