$derived
派生状态用 $derived
符文声明:
¥Derived state is declared with the $derived
rune:
<script>
let count = $state(0);
let doubled = $derived(count * 2);
</script>
<button onclick={() => count++}>
{doubled}
</button>
<p>{count} doubled is {doubled}</p>
$derived(...)
中的表达式应该没有副作用。Svelte 将禁止在派生表达式内更改状态(例如 count++
)。
¥The expression inside $derived(...)
should be free of side-effects. Svelte will disallow state changes (e.g. count++
) inside derived expressions.
与 $state
一样,你可以将类字段标记为 $derived
。
¥As with $state
, you can mark class fields as $derived
.
Svelte 组件中的代码在创建时只执行一次。如果没有
$derived
符文,即使count
发生变化,doubled
也会保持其原始值。¥[!NOTE] Code in Svelte components is only executed once at creation. Without the
$derived
rune,doubled
would maintain its original value even whencount
changes.
$derived.by
有时你需要创建不适合简短表达式的复杂派生。在这些情况下,你可以使用接受函数作为其参数的 $derived.by
。
¥Sometimes you need to create complex derivations that don’t fit inside a short expression. In these cases, you can use $derived.by
which accepts a function as its argument.
<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)
。
¥In essence, $derived(expression)
is equivalent to $derived.by(() => expression)
.
了解依赖(Understanding dependencies)
¥Understanding dependencies
在 $derived
表达式(或 $derived.by
函数体)内同步读取的任何内容都被视为派生状态的依赖。当状态发生变化时,派生将被标记为脏,并在下次读取时重新计算。
¥Anything read synchronously inside the $derived
expression (or $derived.by
function body) is considered a dependency of the derived state. When the state changes, the derived will be marked as dirty and recalculated when it is next read.
要使某个状态不被视为依赖,请使用 untrack
。
¥To exempt a piece of state from being treated as a dependency, use untrack
.
更新传播(Update propagation)
¥Update propagation
Svelte 使用一种称为推拉反应性的东西 - 当状态更新时,依赖于状态的所有内容(无论是直接还是间接)都会立即收到更改通知(’push’),但派生值不会重新评估,直到实际读取它们(’pull’)。
¥Svelte uses something called push-pull reactivity — when state is updated, everything that depends on the state (whether directly or indirectly) is immediately notified of the change (the ‘push’), but derived values are not re-evaluated until they are actually read (the ‘pull’).
如果派生的新值在引用上与其先前的值相同,则将跳过下游更新。换句话说,Svelte 只会在 large
更改时更新按钮内的文本,而不会在 count
更改时更新,即使 large
依赖于 count
:
¥If the new value of a derived is referentially identical to its previous value, downstream updates will be skipped. In other words, Svelte will only update the text inside the button when large
changes, not when count
changes, even though large
depends on count
:
<script>
let count = $state(0);
let large = $derived(count > 10);
</script>
<button onclick={() => count++}>
{large}
</button>