走到這裡,這個關於 Signal 與 Fine-grained Reactivity 的系列文章,暫時告一個段落。
這篇不談新的技術細節,而是一些我的心得與反思。
這整個系列,某種程度上是受到 Solid.js 作者 Ryan Carniato 的啟發。
他總能一針見血地指出我們在 React 開發中面臨的痛點。
作為一個資深 React 工程師,我常常覺得「對,這就是我每天遇到的問題!」。
Solid.js 本身無疑是一個優秀的框架,但對新手而言門檻不低。
不過,對我來說,它所做的很多設計選擇,比 React 的發展方向更合理,比如: 去掉 dependenices array 的 effect、讓 Mounted 與 Cleanup 獨立開來、拔掉 V-DOM 的 JSX...,這些都是之前 React 社群裡呼聲很高但不被重視的需求。
這幾年 React 的走向越來越受到 Vercel 的影響。
Server Components 被強推,讓前端工程師不得不接受還不成熟的模式。
老實說,我反而比較懷念「沒有 Server Components 的 Next.js」,那個時代的 React 更單純,缺點雖然明顯,但至少我們能自由選擇解法。
社群裡有人提出過「React 是否應該引入 signal」甚至「考慮無 VDOM 版本」,但這可能與金主 Vercel 的利益衝突。
結果,我看到的,是一種 React 末日餘暉的樣態。
雖然像 TanStack 還在努力支撐,但如果未來出現成熟的替代方案,我大概也不會再選 Next。
社群上有時會聽到一些說法,認為 Jotai(或 Atomic 模型)和 Signal 的做法相同,而且因為依附框架生態,更加友好。
但如果你跟著這系列文章一起實作,或曾經實際動手實作過,就能理解兩者其實有著截然不同的設計理念,關鍵差異在於「是否處理依賴關係」。
下面我簡單對比一下兩者概念上的差異。
computed
/ effect
會在執行時自動註冊依賴 → 之後來源值變動時,自動通知下游。一句話比較兩者概念上的差異:
不處理依賴關係,寫起來確實很輕鬆;而且 Jotai 採用框架本身提供的狀態單元來管理,天然就能符合各框架的生命週期,避免同步問題。
但相對地,這樣的模式必須「靠框架 re-render」來保證正確性,而不像 Signal 能透過 runtime 的依賴追蹤做到更細粒度的更新。
常常有人把 Signal 與 Vue/React 的整合,類比成傳統 OOP 世界的 Dependency Injection (DI)。
表面上看起來確實有一點像:把外部狀態「注入」到框架內使用。
但本質差異在於:
看似相似,其實解決的維度完全不同。
Car
需要 Engine
,由 DI 框架幫你塞進去class Engine {}
class Car {
constructor(private engine: Engine) {}
}
totalPrice
依賴 count * unitPrice
,自動跟著變const count = signal(2);
const unitPrice = signal(100);
const totalPrice = computed(() => count.get() * unitPrice.get());
很多人以為 Signal 只是新的 state management,但經過我們這系列深入的實作,你會發現它所觸及的領域,不僅僅只是狀態管理工具這麼簡單。
真正讓人恐懼的,是它逼我們去反思 VDOM 是否仍然必要。
一旦這種思維普及,過去圍繞在 VDOM 的知識體系與教學產業鏈,就會被動搖。
這也是為什麼有些人會本能地排斥,甚至貶低。
技術的演進,從來不只是程式碼的事,也是利益結構的事。
Signal 真正動搖的,不是 state,而是整個 VDOM 信仰。
有些人會直接否定 Signal,甚至用嘲諷的語氣說:「Signal 沒用啦!」、「Dan 都叫你別用!」
這種言論常常帶有情緒或立場色彩,而不是基於對技術本身的理解。
對我而言,這些聲音並不構成威脅,反而像是一面鏡子:
所以,遇到這類攻擊時最好的態度是 不急於反駁,而是回到程式碼與設計原理本身。
當你能用簡單的範例解釋「依賴追蹤的差異」時,這些嘲諷自然就失去力量。
基本上都是很看好的,從去年的 TC-39 signal proposal 就不難看出它在前端應用的地位是越來越重要了,除了 React 還在營造「大哥是對的」的氛圍外,其餘主流框架全都導入 signal 應用進入新的紀元,比如:Vue 的 Vapor mode、Angular 17+ 的 signal、Svelte rune、preact signal、solidjs ...,有的甚至已經在往拔除不需要的 V-DOM (EX:Vue 的 Vapor mode、solidjs JSX setting) 方向邁進。
所以能掌握這個概念的核心,在未來的應用場景就能比較得心應手。
以我自己為例,掌握這個概念之後我跳轉不同框架時,就非常容易上手。
會開啟這個系列,其實是因為我在開發自己開源的 Signal System Library -- segnale-react。
在這個過程中,我不斷遇到挑戰,才發現:
過去在學校或面試題裡那些「演算法與資料結構」的東西,原來在這裡都能派上用場。
這也讓我更確信:
想設計好框架的底層,就必須掌握 JS 基礎與計算機科學的知識。
這個系列對我來說,不只是技術筆記,更是一段心路歷程:
最大的體會是:
框架會更替,但基礎知識與思維模式才是能走得更遠的東西。
這系列文章,還僅僅只是扒開框架引擎裡的第一層 Reactive Core,當然也是每個框架最為核心的基石,如果要往下延伸,還會遇到 DOM Render / UI Render Scheduler / Component Model 等問題,每個框架都有選擇上的考量和取捨,這部分應該會是我日後研究的方向吧!
如果你正在學習 React,其實不需要急著跳到 Solid.js 或其他框架。
因為真正重要的不是「框架選擇」,而是理解底層觀念:
只要掌握這些,你就能在任何框架裡快速找到方向。
別只學會用框架,更要理解它的底層邏輯。
潮流會變,但基礎概念才是工程師能帶走的真正資產。
這邊還是附上系列文章中,實作的程式碼給大家參考,這還有包含每個段落的 Unit test,但只針對有異動的部分。
基本上還是希望讀者們自己參考我的範例去更改,不要只是整段複製貼上,這樣一來你會失去很多細節思考的機會。
我提供的範例是有經過考量才選擇的做法,很多時候在資料結構與訂閱制度的選擇上,未必符合所有開發需求,但會比較讓初學者容易理解概念,不會跳來跳去切換不同的算法和資料結構,導致講解過程中不必要的錯亂。
比較進階的探討會聚焦在 Ryan Carniato 這個系列文章的內容,也是目前主流 Signal 發展的取捨。
最後,分享一段我很喜歡的港片橋段,搶錢夫妻的那段最後的播報:
他說什麼,你什麼都相信了,那麼你們有沒有懷疑過,他們可能也在騙你,也許是假的,也許他也是不能肯定的,也許也跟我和電視台一樣,為了能多賺點錢,多賺點收視率,這麼簡單為甚麼你沒有留意呢?
電視台給我們看什麼,我們就看什麼,報紙寫什麼我們就相信什麼,偶像穿什麼,我們就穿些什麼,廣告說什麼好吃,我們就把他們都買回來,大家都沒有用腦子對不對,反正你說什麼我們就做什麼;一個人穿牛仔褲,這世界都穿牛仔褲了,這個世界只有牛仔褲了嗎? 不可能嘛!
你們是傳播界老大,你們說什麼我們當然相信了,那麼坐在家裏面打開電視機,叫我們相信什麼說什麼,我們懂什麼呢? 話不是這麼說,你們要用思考,不能光靠眼睛和耳朵,一定要用腦袋想想,我覺得能靠的就是這個了。
這段雖然是呼籲我們要帶著腦子看新聞,但放在開發領域又何嘗不是呢?
Youtuber 給我們看什麼,我們就看什麼,AI 寫什麼我們就相信什麼,線上課程教什麼,我們就用些什麼,廣告說什麼好用,我們就把技術全部轉移過去...,一個人用 React,這世界都用 React,這個世界只有 React 了嗎? 不可能嘛!
希望這系列文章,能帶給大家用不同角度思考,重新審視那些既定的規則與假設,跳脫原本的思想框架,能更清楚的認知到,我們所用的工具在解決什麼必要的需求,不要只是盲從。