Skip to content

$derived 派生

$derived 用于从一个或多个状态计算出新值。它会自动追踪依赖,只有依赖变化时才重新计算。

基本用法

svelte
<script>
  let count = $state(0);

  // doubled 依赖 count;count 变,doubled 自动重算
  let doubled = $derived(count * 2);
</script>

<button onclick={() => count++}>{count}</button>
<p>它的两倍是 {doubled}</p>

取代 Svelte 4 的 $:

在 Svelte 4 里,派生值用响应式语句 $: 表示:

svelte
<!-- Svelte 4 写法(已过时) -->
<script>
  let count = 0;
  $: doubled = count * 2;
</script>

$: 的问题在于:它的触发时机依赖编译器分析,容易让人困惑(「为什么这个没触发?」)。$derived 把它变成了一个显式的函数调用,依赖关系一目了然。

$derived vs $derived.by

当派生逻辑需要多条语句时,用 $derived.by 传入一个函数:

svelte
<script>
  let items = $state([
    { name: '苹果', price: 5, qty: 2 },
    { name: '香蕉', price: 3, qty: 4 }
  ]);

  // 简单表达式用 $derived
  const count = $derived(items.length);

  // 多语句逻辑用 $derived.by(() => { ... })
  const total = $derived.by(() => {
    let sum = 0;
    for (const item of items) {
      sum += item.price * item.qty;
    }
    return sum;
  });
</script>

<p>共 {count} 种商品,总价 {total} 元</p>

TIP

$derived(expr) 适合一行表达式;$derived.by(fn) 适合需要中间变量、循环、提前返回的复杂逻辑。

派生值是只读的

不要给 $derived 的结果赋值 —— 它由依赖决定:

svelte
<script>
  let count = $state(0);
  let doubled = $derived(count * 2);

  // ❌ 错误:doubled 是只读的派生值
  // doubled = 10;
</script>

如果你想「改一个值让另一个跟着变」,用 $derived 单向派生即可;如果需要双向,看 $props 与 $bindable

派生可以依赖派生

依赖链会自动串起来:

svelte
<script>
  let price = $state(100);
  let qty = $state(2);

  const subtotal = $derived(price * qty);
  const tax = $derived(subtotal * 0.1);   // 依赖 subtotal
  const total = $derived(subtotal + tax); // 依赖 subtotal、tax
</script>

任何一个源头变化,整条链都会精确地重算。

试一试

拖动滑块,面积、周长、形状判断都是 $derived 实时算出来的:

派生状态 · $derivedSvelte 5 · Live

对应源码:

svelte
<script>
  let width = $state(10);
  let height = $state(5);

  const area = $derived(width * height);
  const perimeter = $derived(2 * (width + height));
  const isSquare = $derived(width === height);
</script>

<input type="range" bind:value={width} />
<input type="range" bind:value={height} />

<div style:width="{width * 12}px" style:height="{height * 12}px"></div>

<p>面积 {area},周长 {perimeter},{isSquare ? '正方形' : '长方形'}</p>

小结

要点说明
$derived(expr)由依赖自动重算的派生值
$derived.by(fn)多语句派生逻辑
只读不能给派生值赋值
自动追踪依赖变化才重算,支持派生链
取代Svelte 4 的 $: 响应式语句

下一步:$effect 副作用

基于 VitePress 构建 · 示例使用 Svelte 5.57