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 を使用します。

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

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

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

Edit this page on GitHub

previous next