Skip to main content

$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 が変更されても更新されません (たとえ largecount に依存していたとしても):

<script>
	let count = $state(0);
	let large = $derived(count > 10);
</script>

<button onclick={() => count++}>
	{large}
</button>

Edit this page on GitHub

previous next