Skip to main content

$derived

派生状态使用 $derived 符号声明:

<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++)。

$state一样,您可以标记类字段为$derived

[注意] Svelte 组件中的代码仅在创建时执行一次。如果没有$derived运行,doubled即使在count变化时也会保持其原始值。

$derived.by

有时您需要创建不适合简短表达式的复杂推导。在这种情况下,您可以使用$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 函数体)内同步读取的内容都被视为派生状态的 依赖。当状态发生变化时,派生状态将被标记为 ,并在下一次读取时重新计算。

为将某个状态从依赖项处理中豁免,请使用 untrack

覆盖派生值

派生表达式在其依赖项更改时会被重新计算,但您可以通过重新分配它们来临时覆盖它们的值(除非它们被声明为const)。这可以用于诸如乐观的用户界面等情况,其中值是从“真相来源”(例如您的服务器上的数据)派生出来的,但您希望向用户显示即时反馈:

<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>

[注意] 在 Svelte 5.25 之前,派生变量是只读的。

派生和反应性

不同于$state,它将对象和数组转换为深度响应式代理,$derived值保持原样。例如,在这种情况下...

let items = $state([...]);

let index = $state(0);
let selected = $derived(items[index]);

...您可以更改(或 绑定:选定的属性,这将影响底层的items数组。如果items不是深度响应式的,修改selected将没有效果。

解构

如果您使用与$derived声明一起的解构,则生成的所有变量都将具有响应性——这...

let { let a: numbera, let b: numberb, let c: numberc } = 
function $derived<{
    a: number;
    b: number;
    c: number;
}>(expression: {
    a: number;
    b: number;
    c: number;
}): {
    a: number;
    b: number;
    c: number;
}
namespace $derived

Declares derived state, i.e. one that depends on other state variables. The expression inside $derived(...) should be free of side-effects.

Example:

let double = $derived(count * 2);

https://svelte.dev/docs/svelte/$derived

@paramexpression The derived state expression
$derived
(
function stuff(): {
    a: number;
    b: number;
    c: number;
}
stuff
());

...大致相当于这个:

let 
let _stuff: {
    a: number;
    b: number;
    c: number;
}
_stuff
=
function $derived<{
    a: number;
    b: number;
    c: number;
}>(expression: {
    a: number;
    b: number;
    c: number;
}): {
    a: number;
    b: number;
    c: number;
}
namespace $derived

Declares derived state, i.e. one that depends on other state variables. The expression inside $derived(...) should be free of side-effects.

Example:

let double = $derived(count * 2);

https://svelte.dev/docs/svelte/$derived

@paramexpression The derived state expression
$derived
(
function stuff(): {
    a: number;
    b: number;
    c: number;
}
stuff
());
let let a: numbera =
function $derived<number>(expression: number): number
namespace $derived

Declares derived state, i.e. one that depends on other state variables. The expression inside $derived(...) should be free of side-effects.

Example:

let double = $derived(count * 2);

https://svelte.dev/docs/svelte/$derived

@paramexpression The derived state expression
$derived
(
let _stuff: {
    a: number;
    b: number;
    c: number;
}
_stuff
.a: numbera);
let let b: numberb =
function $derived<number>(expression: number): number
namespace $derived

Declares derived state, i.e. one that depends on other state variables. The expression inside $derived(...) should be free of side-effects.

Example:

let double = $derived(count * 2);

https://svelte.dev/docs/svelte/$derived

@paramexpression The derived state expression
$derived
(
let _stuff: {
    a: number;
    b: number;
    c: number;
}
_stuff
.b: numberb);
let let c: numberc =
function $derived<number>(expression: number): number
namespace $derived

Declares derived state, i.e. one that depends on other state variables. The expression inside $derived(...) should be free of side-effects.

Example:

let double = $derived(count * 2);

https://svelte.dev/docs/svelte/$derived

@paramexpression The derived state expression
$derived
(
let _stuff: {
    a: number;
    b: number;
    c: number;
}
_stuff
.c: numberc);

更新传播

Svelte 使用一种称为推拉响应性的技术——当状态更新时,所有依赖于状态(无论是直接还是间接)的内容都会立即收到变更通知(即“推”),但派生值不会在实际上读取之前重新评估(即“拉”)。

如果派生值与其之前的值在引用上相同,则将跳过下游更新。换句话说,只有当 large 发生变化时,Svelte 才会更新按钮内的文本,而不是当 count 发生变化时,即使 large 依赖于 count

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

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

Edit this page on GitHub llms.txt

previous next