iT邦幫忙

2025 iThome 鐵人賽

DAY 8
2

引言

在上一篇中,我們拆解了 Dependency Tracking 的核心概念與執行原理,本篇將焦點放在 React 的 dependency 模型:它的特性、限制,以及與 Signals 顯式依賴圖的對比。

React 的依賴模型是什麼?

React 並沒有內建顯式的依賴追蹤圖,它的運作模式是:

  1. 狀態更新(setState execute):
    觸發整個 Component 重新執行 render function。
  2. 重新渲染(Reconciliation):
    React 透過 Virtual DOM 比對新舊樹狀結構(diffing),決定哪些部分需要更新。
  3. Effects 執行(useEffect/useLayoutEffect):
    在 commit 階段依照依賴陣列(dependency array)決定是否重新執行副作用。

https://ithelp.ithome.com.tw/upload/images/20250811/20129020aq2AlS2HPY.png

這是一種 Pull-based + Scheduler 模式:React 並不知道某個 state 與哪些 UI 節點直接相關,只能「重新拉一次整個 component」來確保正確性。

React 的 dependency tracking 問題點

問題類型 描述 影響
缺乏顯式依賴圖 React 無法精準知道哪個 state 對應到哪段 UI 導致不必要的 re-render
依賴陣列手動維護 useEffect 必須手動列出依賴,錯漏容易發生 造成 bug 或無謂的 effect 觸發
重複計算 多個 component 讀取相同 state 時,各自觸發渲染 效能浪費,尤其在大型應用
難以處理動態依賴 依賴關係需手動管理,條件式邏輯繁瑣 增加維護成本

Signals 的對比優勢

Signals(以 Solid.js、MobX、Vue ref 為例)在這些方面有所改善:

  • 顯式依賴圖:
    • get 時自動收集依賴,set 時只通知真正需要更新的 effect/computed。
  • 精細更新:
    • 任意值級別更新,而非 component 級別。
  • 免手動依賴管理:
    • 動態依賴可在執行期自動增減,避免依賴陣列錯誤。
  • 減少重複計算:
    • 共用的 computed 只計算一次,結果分發給多處使用。

範例對比

React

function Counter() {
  const [count, setCount] = useState(0);
  const double = count * 2; // 每次渲染都重算

  return (
    <>
      <h1>Hello World!</h1>
      <button onClick={() => setCount(c => c + 1)}>{double}</button>;
    </>
  );
}
  • count 更新 → Counter 整個重新渲染(包含Hello World) → double 重算。

Signal

const [count, setCount] = createSignal(0);
const double = () => count() * 2;
function Counter() {
  return (
    <>
      <h1>Hello World!</h1>
      <button onClick={() => setCount(c => c + 1)}>{double()}</button>;
    </>
  );
}
  • count 更新 → 只重算 double → 只更新使用它的 DOM 節點(只有 button 會被更新)。

React 為何仍能屹立不搖?

雖然 React 缺乏顯式 dependency tracking,但它藉由以下策略緩解問題:

  • Virtual DOM diff 最佳化(例如 keymemo
  • 批次更新(automatic batching)
  • 選擇性渲染(React.memouseMemouseCallback

這些補救方案雖然提升了效能,但開發者仍需手動調整最佳化。

所以常會聽到:

「React 只是 library,library 怎麼會處理那些任務,那是 framework 的工作。」
「Batching 很正常吧! 有程式語言基礎的都應該要知道阿!」
「JS 程度不好就先練,不要抱怨那些 Javascript 基礎觀念的東西!」

這些話確實會讓一些新手鬼轉其他框架,這樣的態度也讓他們總是不找找自己問題!
檢討開發者,先貶低新手,再推銷一波課程:
https://ithelp.ithome.com.tw/upload/images/20250811/20129020orBY7SdgF0.png

我手邊有批「React 效能優化實戰」的課程,能讓你擺脫菜味,很便宜的,有沒有興趣參考一下!

這樣的養套殺,培養了一坨很大的教學產業鏈,死忠的支持者永遠會為自己找到合適的藉口。

以上純屬現象觀察,沒有要引戰,我也是從一個懵懵懂懂的 React 仔慢慢走過來的。

結語

從今天的這篇介紹,我們可以得到下列重點:

  • React 屬於 Pull-based 模型,無顯式依賴圖,導致部分更新無法精細化。
  • Signals 採用 Push-based + 顯式依賴圖,自動管理依賴並只更新必要部分。

在對效能敏感或依賴關係複雜的應用中,Signals 模型有顯著優勢。

下一篇,我們從實作層面來慢慢推導出一個簡易的 Signal 範例。


上一篇
Dependency Tracking 基本原理(I)
下一篇
實作 Signal 前你需要的兩個 JS 基礎觀念
系列文
Reactivity 小技巧大變革:掌握 Signals 就這麼簡單!9
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

1
Dylan
iT邦研究生 5 級 ‧ 2025-09-08 09:19:15

寫 react 的真的整天都在談優化XD

LucianoLee iT邦研究生 4 級 ‧ 2025-09-08 12:29:17 檢舉

我的觀察是,會談效能優化議題的,都只限於 React 生態,在最後一定會推銷一下自己的付費課程。

我要留言

立即登入留言