Skip to content

Svelte 5 稳定版:全面拥抱 Runes

Svelte 5 稳定版已经发布一段时间了,Runes 系统是最大的变化。来对比一下 Svelte 4 和 Svelte 5 的写法差异。

Runes 是什么

Runes = Svelte 5 的响应式原语
类似 Vue 的 ref/reactive,但语法更简洁

核心 Runes:
  $state       → 响应式状态
  $derived     → 派生状态(计算属性)
  $effect      → 副作用
  $props       → 组件属性
  $bindable    → 可绑定属性
  $inspect     → 调试用

$state:响应式状态

svelte
<!-- Svelte 4 -->
<script>
  let count = 0;
  let user = { name: "张三", age: 25 };

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

  function updateUser() {
    user.age += 1; // 嵌套属性需要特殊处理
    user = user;   // 手动触发更新
  }
</script>

<!-- Svelte 5 -->
<script>
  let count = $state(0);
  let user = $state({ name: "张三", age: 25 });

  function increment() {
    count += 1; // 自动响应
  }

  function updateUser() {
    user.age += 1; // 深层响应式,自动触发更新
  }
</script>

$derived:派生状态

svelte
<!-- Svelte 4 -->
<script>
  let items = [1, 2, 3, 4, 5];
  $: total = items.reduce((a, b) => a + b, 0);
  $: average = total / items.length;
  $: doubled = items.map(n => n * 2);
</script>

<!-- Svelte 5 -->
<script>
  let items = $state([1, 2, 3, 4, 5]);
  const total = $derived(items.reduce((a, b) => a + b, 0));
  const average = $derived(total / items.length);
  const doubled = $derived(items.map(n => n * 2));

  // 带副作用的派生
  let sorted = $derived.by(() => {
    console.log("重新排序");
    return [...items].sort((a, b) => a - b);
  });
</script>

$effect:副作用

svelte
<!-- Svelte 4 -->
<script>
  let count = 0;

  $: {
    console.log("count 变了:", count);
    document.title = `点击了 ${count} 次`;
  }

  $: if (count > 10) {
    console.log("太多了!");
  }
</script>

<!-- Svelte 5 -->
<script>
  let count = $state(0);

  $effect(() => {
    console.log("count 变了:", count);
    document.title = `点击了 ${count} 次`;

    // cleanup 函数
    return () => {
      console.log("effect 清理");
    };
  });

  // 只在特定时机运行
  $effect.pre(() => {
    // DOM 更新前运行
    console.log("即将更新 DOM");
  });
</script>

$props:组件属性

svelte
<!-- Svelte 4 -->
<script>
  export let name;
  export let age = 25;
  export let className = "";

  // $$restProps 处理剩余属性
</script>

<div class={className} {...$$restProps}>
  {name}, {age}岁
</div>

<!-- Svelte 5 -->
<script>
  let { name, age = 25, className = "", ...rest } = $props<{
    name: string;
    age?: number;
    className?: string;
  }>();
</script>

<div class={className} {...rest}>
  {name}, {age}岁
</div>

$bindable:双向绑定

svelte
<!-- 子组件 Input.svelte -->
<script>
  let { value = $bindable(""), placeholder = "请输入" } = $props<{
    value?: string;
    placeholder?: string;
  }>();
</script>

<input bind:value {placeholder} />

<!-- 父组件 -->
<script>
  let searchQuery = $state("");
</script>

<Input bind:value={searchQuery} />
<p>搜索:{searchQuery}</p>

组件事件 vs 回调

svelte
<!-- Svelte 4:使用 createEventDispatcher -->
<script>
  import { createEventDispatcher } from "svelte";
  const dispatch = createEventDispatcher();

  function handleClick() {
    dispatch("select", { id: 1 });
  }
</script>

<button on:click={handleClick}>选择</button>

<!-- S�velte 5:直接用回调函数 -->
<script>
  let { onSelect } = $props<{
    onSelect?: (data: { id: number }) => void;
  }>();
</script>

<button onclick={() => onSelect?.({ id: 1 })}>选择</button>

<!-- 父组件 -->
<script>
  function handleSelect(data: { id: number }) {
    console.log("选中:", data.id);
  }
</script>

<MyComponent onSelect={handleSelect} />
<!-- 不再需要 on: 语法 -->

与 React/Vue 的对比

概念对比:

              React 19      Vue 3.5       Svelte 5
──────────────────────────────────────────────────────
状态          useState      ref()         $state()
派生          useMemo       computed()    $derived()
副作用        useEffect     watch()       $effect()
属性          props         defineProps   $props()
双向绑定      -             v-model       $bindable()

语法简洁度:Svelte > Vue > React
类型安全:  Svelte ≈ Vue > React
生态成熟度:React > Vue > Svelte

迁移策略

Svelte 4 → 5 迁移:

1. 渐进式迁移:Svelte 5 向后兼容 Svelte 4 语法
2. 自动迁移工具:npx sv migrate svelte-5
3. 优先迁移:新组件用 Svelte 5 写法
4. 后续迁移:逐步改造老组件

小结

  • Svelte 5 的 Runes 系统让响应式更显式、更可预测
  • $state、$derived、$effect 三件套覆盖了大部分场景
  • $props 替代 export let,类型安全更好
  • 回调替代 createEventDispatcher,API 更简洁
  • Svelte 5 向后兼容,可以渐进式迁移
  • 对于小型项目和性能敏感场景,Svelte 依然是好选择

MIT Licensed