Skip to content

$effect 副作用

$effect 用于在响应式依赖变化后,运行副作用代码。副作用指的是:和「外部世界」交互的操作 —— 操作 DOM、发请求、写 localStorage、设置定时器等。

基本用法

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

  // 每当 count 变化,这段代码就在 DOM 更新后运行
  $effect(() => {
    console.log(`count 现在是 ${count}`);
  });
</script>

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

打开浏览器控制台,每次点击都会看到日志。

何时运行

  • 首次:组件挂载后运行一次
  • 之后:当它读取过的响应式值发生变化时,在 DOM 更新之后重新运行

$effect自动追踪它在函数体里读取到的响应式依赖,无需手动声明。

清理函数

如果副作用需要清理(取消订阅、清除定时器等),返回一个函数:

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

  $effect(() => {
    const id = setInterval(() => {
      seconds += 1;
    }, 1000);

    // 返回的函数会在下次运行前、以及组件销毁时调用
    return () => clearInterval(id);
  });
</script>

<p>页面已打开 {seconds} 秒</p>

慎用 $effect

大多数情况你不需要 $effect

一个常见的误区是把 $effect 当成「状态一变就跑一下」的万能工具。如果你只是想根据状态计算一个新值,应该用 $derived;如果只是想在事件发生时做点什么,直接写在事件处理函数里。

$effect 的真正用途是同步响应式系统之外的东西:

想做的事应该用
根据状态算出新值$derived
响应用户操作事件处理函数(onclick 等)
操作第三方库 / 原生 DOM$effect
localStorage、网络、定时器同步$effect

比如,把状态同步到 localStorage

svelte
<script>
  let theme = $state('light');

  // 这是合理的 $effect 用法:与「外部世界」(浏览器存储)同步
  $effect(() => {
    localStorage.setItem('theme', theme);
  });
</script>

<button onclick={() => (theme = theme === 'light' ? 'dark' : 'light')}>
  当前主题:{theme}
</button>

$effect.pre —— 在 DOM 更新前运行

如果你需要在 DOM 更新之前做点事(比如测量旧的布局),用 $effect.pre

svelte
<script>
  let items = $state(['a', 'b']);

  $effect.pre(() => {
    // 在 DOM 更新前运行,可读取更新前的 DOM 状态
    console.log('即将更新,当前列表长度', items.length);
  });
</script>

在真实示例里观察

本站的待办示例里就用 $effect 把「剩余任务数」打印到控制台。添加/勾选任务时,打开 DevTools 的 Console 面板就能看到:

svelte
$effect(() => {
  console.log(`[Todo demo] 剩余 ${remaining} 项,共 ${todos.length} 项`);
});
待办清单 · 综合实战Svelte 5 · Live

小结

要点说明
$effect(fn)依赖变化后、DOM 更新后运行
自动追踪依赖读取哪些响应式值就依赖哪些
返回清理函数用于取消订阅 / 清除定时器
$effect.pre在 DOM 更新前运行
谨慎使用计算值用 $derived,事件用处理函数

下一步:$props 与绑定 —— 组件之间如何传递数据。

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