Skip to content

$state、$derived、$effect ​

Svelte 5 的 runes 把“可写状态”“纯派生值”“外部副作用”分开。$derived 应由输入计算出结果;$effect 用于同步 DOM、网络或第三方库,不能把派生值再写回 state 形成循环。

最小可运行组件 ​

svelte
<script>
  let count = $state(0)
  let doubled = $derived(count * 2)
  let input
  $effect(() => {
    document.title = `count=${count}`
    return () => { document.title = 'Svelte demo' }
  })
</script>

<button onclick={() => count++}>count: {count}</button>
<p bind:this={input}>double: {doubled}</p>

点击按钮后只需观察 count、doubled 和页面标题:派生值同步更新,effect 在组件销毁时执行清理。把 doubled 改为在 effect 中 doubled = count * 2 会引入额外写入,甚至形成更新循环。

更新追踪与异步边界 ​

rune 表达式只追踪本次运行实际读取的状态。异步回调中捕获的值可能已经过期,因此请求要保存序号或 AbortController;effect 清理函数先取消旧请求,再提交新结果。服务端渲染阶段没有 window,浏览器 API 必须放进 effect 或 onMount 等客户端边界。

选择与排错 ​

  • 纯计算用 $derived,不要为它再建一个可写 state。
  • 订阅、计时器、DOM API 和第三方实例用 $effect,并返回对称清理。
  • 需要跨组件共享时使用 store;不要把模块级可变变量当成隐式全局状态。

练习 ​

  1. 将搜索框示例改为请求取消:新关键词到来时取消旧请求,并显示 loading/error/empty 三态。
  2. 删除一个 effect 写回,改成 $derived,比较更新次数和结果。
  3. 在组件销毁后检查定时器、订阅和 document.title 是否恢复。

查看本节答案

用心记录每一步成长