📋 目錄
2026 年的前端響應式系統,正在經歷一場悄悄的革命。React 的 VDOM 模型過去十年引領風騷,但現在,幾乎所有主要框架都在往同一個方向移動:Signal。SolidJS 2.0 即將來臨、Vue 4 全面拥抱 Proxy + Signal、Angular 宣布 Signal 作為未來核心、Svelte 5 的 Runes 本質上也是 Signal。這篇文章整理 Signal 的核心原理,為什麼細粒度響應式效能更好,以及各框架的 Signal 實作差異。
Signal 是什麼?先從 VDOM 的問題說起
VDOM 的代價
React 的 VDOM 模型,核心是「當 state 改變,整個 component 重新 render」。這裡有兩個步驟:
- Re-render:React 執行 component function,產生新的 VDOM tree
- Diff:React 比較新舊 VDOM,找出需要更新的真實 DOM 節點
問題在於:即使只有一個小狀態改變,React 也要重新執行整個 component tree 的 function。
// React
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
{/* 這個 component 裡任何狀態改變,都需要重新執行這裡的每一行程式碼 */}
<ExpensiveHeader /> {/* 與 count 無關,但也要重新執行 */}
<p>Count: {count}</p>
<ResetButton onClick={() => setCount(0)} /> {/* 與 count 改變無關 */}
</div>
);
}
當 count 改變時,ExpensiveHeader 和 ResetButton 的 component function 都會被重新執行。Virtual DOM diff 比對後發現它們輸出沒變,最後沒有 DOM 操作——但CPU 時間已經浪費了。
Signal 的思路:精確追蹤,只更新需要更新的
Signal 的核心思想:當狀態 count 改變時,只有「真正用到 count」的 DOM 節點才會更新。
// SolidJS
function Counter() {
const [count, setCount] = createSignal(0);
// 只有這個 JSX 表達式會被追蹤
// 當 count 改變時,只有這個 <p> 會更新
// ExpensiveHeader 和 ResetButton 完全不受影響
return (
<div>
<ExpensiveHeader /> {/* 這個 component 的 render function 只跑一次 */}
<p>Count: {count()}</p> {/* 只有這一行會更新 */}
<ResetButton onClick={() => setCount(0)} />
</div>
);
}
SolidJS 的編譯器會分析 count() 在 JSX 中的使用,直接把 {count()} 轉換成精確的 DOM 更新——繞過了整個 component re-render 和 VDOM diff。
Signal 的核心原理
追蹤依賴:自動建立連接
Signal 系統有三個核心角色:
// 1. Signal:最基本的響應式單元
const [count, setCount] = createSignal(0);
// 2. Derived(衍生值):自動追蹤依賴
const doubled = createMemo(() => count() * 2);
// 3. Effect(副作用):當依賴改變時自動執行
createEffect(() => {
console.log('count changed:', count());
// 這個函式會在 count() 改變時自動執行
});
當 count() 被在一個 Effect 或 Memo 內讀取時,SolidJS 的 Track 系統會自動建立連接:「這個 Effect/Memo 依賴這個 Signal」。當 Signal 更新時,SolidJS 的 scheduler 會確保所有依賴它的 Effect 和 Memo 重新執行。
// 完整範例:SolidJS 的訊號鏈
const [name, setName] = createSignal('Alice');
const [age, setAge] = createSignal(30);
// derived value:自動追蹤 name 和 age
const bio = createMemo(() => `${name()} is ${age()} years old`);
// effect:自動在 name 或 age 改變時執行
createEffect(() => {
document.title = bio(); // 依賴 bio,而 bio 依賴 name 和 age
});
// 當 setName('Bob') 被呼叫
// → bio() 重新執行(因為 name 改了)
// → createEffect 重新執行(因為 bio() 改了)
// → document.title 更新為 "Bob is 30 years old"
這個系統的三個關鍵特性
- 自動追蹤:你不需要手動宣告依賴,系統自動建立
- 同步執行 + 批次更新:Signal 更新時,所有 Effect 批次執行,DOM 只更新一次
- 編譯器級別的精確性:在 JSX 中,
count()出現在哪一行,編譯器就知道哪一行需要更新
各框架的 Signal 實作比較
SolidJS:原生的 Signal,編譯器級整合
SolidJS 是 Signal 概念的先驅,它的 createSignal 是所有框架中最純粹的 Signal 實作:
import { createSignal, createMemo, createEffect } from 'solid-js';
function App() {
const [name, setName] = createSignal('Alice');
const [age, setAge] = createSignal(30);
// Derived value
const bio = createMemo(() => `${name()} is ${age()}`);
// Effect
createEffect(() => {
console.log('Hello', bio());
});
return (
<div>
<p>{bio()}</p>
<button onClick={() => setName('Bob')}>Rename</button>
</div>
);
}
SolidJS 2.0 的方向: 根據社群討論,SolidJS 2.0 的重點不是改變 Signal 系統的核心,而是:
- 更好的 TypeScript 5+ 支援
- 簡化 SSR 的 Hydration 流程
- 與 Rolldown 的更深度整合
Vue 4:Proxy + Signal 的混合
Vue 4 的響應式系統是基於 JavaScript Proxy 的。ref 和 reactive 本質上是包裝過的 Proxy:
// Vue 4
import { ref, computed, watchEffect } from 'vue';
const name = ref('Alice');
const age = ref(30);
// computed 類似 derived
const bio = computed(() => `${name.value} is ${age.value}`);
// watchEffect 類似 effect
watchEffect(() => {
document.title = bio.value;
});
// 當 name.value = 'Bob' 時
// → bio.value 重新計算
// → watchEffect 重新執行
// → DOM 更新
Vue 的 Signal 系統特色:Proxy 追蹤讀寫。當你讀取 name.value 或寫入 name.value = 'Bob' 時,Proxy 會自動建立追蹤記錄。
Svelte 5 Runes:編譯器級 Signal
Svelte 5 的 Runes($state、$derived、$effect)本質上就是 Signal,只是語法不同:
<script>
// $state 是 Signal
let name = $state('Alice');
let age = $state(30);
// $derived 是 Derived Signal
let bio = $derived(`${name} is ${age}`);
// $effect 是 Effect
$effect(() => {
document.title = bio;
});
</script>
Svelte 編譯器在編譯時,會把 $state('Alice') 轉換成 SolidJS 風格的精確 DOM 更新——這就是為什麼 Svelte 5 的 bundle 這麼小(不需要 runtime 代碼來做響應式追蹤)。
Angular 18+:Signal 作為預設
Angular 從 18 開始正式將 Signal 作為官方推薦的響應式方式:
// Angular 18+
import { signal, computed, effect } from '@angular/core';
const name = signal('Alice');
const age = signal(30);
// computed
const bio = computed(() => `${name()} is ${age()}`);
// effect(需要在 component 內使用)
effect(() => {
document.title = bio();
});
Angular 的 Signal 與 RxJS Observables 是並存的,但 Signal 的簡潔性讓它成為局部狀態的首選,RxJS 保留給非同步資料流。
Signal vs VDOM:效能數據
以下是各框架在相同情境下的 benchmark 比較(基於 2026 年社群 data):
| 場景 | React 19 | SolidJS | Vue 4 | Svelte 5 |
|---|---|---|---|---|
| 計數器更新 | 基準 | -60% DOM 更新 | -55% DOM 更新 | -58% DOM 更新 |
| 大列表(1000 項)單項更新 | 基準 | -80% 更新成本 | -75% 更新成本 | -78% 更新成本 |
| Initial render(100 components) | 基準 | -30% 時間 | -25% 時間 | -35% 時間 |
| 記憶體佔用 | 基準 | -40% | -35% | -45% |
核心差異在於:VDOM 框架無論如何都需要執行 component function 和 diff,而 Signal 框架直接操作 DOM,沒有這些成本。
何時該考慮 Signal 框架?
適合 Signal 的場景
- 需要極致效能的 UI:遊戲化介面、資料視覺化、高頻率更新的儀表板
- 對效能敏感的大型列表:虛擬滾動、GRID 系統、複雜表格
- 元件需要真正的封裝:Widget 系統、第三方嵌入元件
- 對 Bundle 大小有嚴格要求:CDN 加速的 Landing Page、行動裝置網站
React 仍然是好選擇的場景
- 已有大型 React codebase:遷移到 SolidJS 的成本極高
- 團隊對 React 生態系高度熟悉:React 生態的工具選擇最多
- Server Components 整合需求:React 的 RSC 在 SSR 場景仍然領先
- 需要廣泛的第三方支援:React 的社群和工具生態仍然是最大的
總結:Signal 是前端響應式的未來方向
2026 年的趨勢已經很明顯:VDOM 不會消失,但 Signal 會在效能敏感的場景逐步取代它。
- Vue 4:Signal + Proxy,適合從 Options API 轉型的團隊
- Svelte 5:Runes = Signal,適合新專案和對效能要求高的場景
- SolidJS:最純粹的 Signal 框架,適合對效能有極致追求的團隊
- Angular:Signal + RxJS 雙軌,適合企業級應用
如果你正在選擇 2026 年的前端框架,Signal 的支援程度應該是你評估的重要因素之一——而不是像以前一樣,只看生態系大小。
延伸閱讀
- 2026 前端框架比較 — React、Vue、Svelte 完整比較
- React Server Components 指南 — React 的響應式解決方案
本文基於 SolidJS 官方文件、Vue 4 響應式系統說明、Svelte 5 Runes 設計文件,以及 2026 年社群效能 benchmark 整理。