$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
を使用します。
更新の伝搬
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>