Skip to content

$state 状态

$state 是 Runes 的基础:声明一个响应式的状态。当它变化时,所有用到它的地方都会自动更新。

基本用法

svelte
<script>
  // count 是响应式的
  let count = $state(0);

  function increment() {
    count += 1; // 直接赋值即可触发更新
  }
</script>

<button onclick={increment}>
  点击了 {count} 次
</button>

对比 Svelte 4:以前 let count = 0 就自动是响应式的,规则藏在编译器的「魔法」里。Svelte 5 用 $state(0) 显式地告诉你(和编译器):这是响应式状态。

深度响应式

$state 不只是浅层的。传入对象或数组时,内部属性也是响应式的

svelte
<script>
  let user = $state({
    name: '张三',
    address: { city: '北京' }
  });
</script>

<button onclick={() => user.name = '李四'}>改名</button>
<button onclick={() => user.address.city = '上海'}>改城市</button>

<p>{user.name} 来自 {user.address.city}</p>

与 Svelte 4 的关键区别

在 Svelte 4 里,user.address.city = '上海' 不会触发更新,你必须写 user = { ...user } 或用 user.address = user.address 这样的赋值。Svelte 5 的 $state 用 Proxy 实现深度响应式,直接改嵌套属性就能触发更新

数组操作变简单了

得益于深度响应式,常见的数组操作可以直接调用方法:

svelte
<script>
  let todos = $state([]);

  function add(text) {
    todos.push({ text, done: false }); // push 直接生效
  }
  function remove(index) {
    todos.splice(index, 1);            // splice 直接生效
  }
</script>

不再需要 todos = [...todos, newTodo] 这样的不可变写法(当然,那种写法依然可用)。

在哪里可以用 $state

$state 可以用在:

  1. 组件的 <script>(最常见)
  2. .svelte.js / .svelte.ts 模块里 —— 这是 Runes 的一大优势:状态可以脱离组件存在,便于复用
js
// counter.svelte.js
export function createCounter(initial = 0) {
  let count = $state(initial);
  return {
    get count() {
      return count;
    },
    increment() {
      count += 1;
    },
    reset() {
      count = initial;
    }
  };
}
svelte
<script>
  import { createCounter } from './counter.svelte.js';
  const counter = createCounter();
</script>

<button onclick={counter.increment}>{counter.count}</button>

文件名有讲究

只有 .svelte.js / .svelte.ts 后缀的模块里才能使用 Runes。普通的 .js 文件里写 $state 会报错。这个约定让编译器知道哪些文件需要特殊处理。

$state.raw —— 不代理的原始值

有时你希望状态不被 Proxy 包裹(例如性能敏感的大型数据、或外部库的对象)。用 $state.raw

svelte
<script>
  let bigData = $state.raw(hugeObject);

  // raw 状态不会深度代理,需要整体替换才触发更新:
  function update(next) {
    bigData = next; // 必须重新赋值
  }
</script>

试一试

下面的计数器就是一个真实的 $state 组件,点一点:

计数器 · $stateSvelte 5 · Live

它的源码:

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

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

小结

要点说明
$state(初始值)声明响应式状态
深度响应式嵌套对象/数组属性变化也会触发更新
直接赋值/方法count++todos.push(...) 都生效
使用位置组件内,或 .svelte.js/.svelte.ts 模块
$state.raw不做 Proxy 代理的原始状态

下一步:用 $derived 从状态计算出派生值。

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