$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 与绑定 —— 组件之间如何传递数据。