$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 可以用在:
- 组件的
<script>里(最常见) .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 从状态计算出派生值。