iT邦幫忙

2026 iThome 鐵人賽

DAY 19
0
Modern Web

Vue 前端工程師視角看 Flutter Web系列 第 19

Day 19|狀態管理選型結論:什麼情境選什麼

  • 分享至 

  • xImage
  •  

模組四|狀態管理(Day 15–19)

先備:Day 15–18(四天的對照)。這一篇是模組四的結論,可以單獨讀,但表格裡每一格背後的理由都在前四天。

四天看完三套半(setState、ChangeNotifier/provider、Riverpod、Bloc),該給結論了。先說我最大的體感落差:在 Vue 圈,狀態管理選型根本不是會議題——路徑早就收斂成一條直線;在 Flutter 圈,這是三分天下的路線之爭,接手每個專案都要先考古它信哪一派。這個差異本身就是選型成本,得算進去。這篇不站隊,給的是一棵可辯護的決策樹——而且會說明:如果你跟我一樣用 AI agent 開發,天平的砝碼會移動。

結論先講:

一般專案選 Riverpod,因為它離 Pinia 最近;而我自己也是這樣選的。

前面幾天我埋了三個落差註記——Day 8 說 demo 沒用 provider、Day 10 和 Day 17 說 demo 沒用 Bloc。今天把帳結清。

Vue 怎麼做

Vue 的選型是一條升級直線,幾乎沒有分岔:

// 第一站:元件內暫態,ref 就好
const isOpen = ref(false)

// 第二站:邏輯要複用,抽 composable
const { user, loading } = useUser(userId)

// 第三站:跨頁面共享,上 Pinia——到站,沒有第四站
export const useCartStore = defineStore('cart', () => { /* ... */ })

每一站的觸發條件明確(要複用→composable;要共享→Pinia),社群共識高到不需要開會。Vuex 退役後連歷史包袱都清掉了。這種「生態收斂」是 Vue 隱形的生產力來源:新人入職零考古成本,AI 寫 Vue 也幾乎不會選錯工具。

Flutter Web 怎麼做

Flutter 官方不欽定方案,只列選項。把四天的對照壓成一張表:

需求 Vue 慣例 Flutter 對應 對照篇
元件內暫態 ref setState Day 7
跨元件共享狀態 Pinia store Riverpod NotifierProvider Day 15–16
同步衍生值 computed Riverpod Provider Day 16
非同步資料 composable / useFetch FutureProvider + AsyncValue Day 16
嚴格狀態機/審計 XState(罕用) Bloc + sealed class Day 17
分層依賴下發 provide/inject InheritedWidget(及其之上的一切) Day 18

我的決策樹,先寫給人類團隊:

  1. 小工具、單頁 demosetState 到底,別急著上架構。
  2. 一般產品 → Riverpod。理由很 Vue 本位:它的心智模型離 Pinia + composable 最近(Day 16 的對照表幾乎一格一格對得上),遷移成本最低,且編譯期防呆最多。
  3. 金融級流程、需要事件溯源、大團隊多人協作 → Bloc。狀態轉移交給編譯器看管的價值,在這些場景蓋過樣板成本。
  4. 混用原則:Riverpod/Bloc 管領域狀態,setState 管純 UI 暫態(展開收合、hover),別把 isExpanded 也塞進全域。

再寫給 agent 工作流,兩個砝碼會移動:

  • 樣板成本趨近零 → Bloc 的最大缺點蒸發(Day 17 的結論),它的適用區間比人手寫時代更寬。
  • 一致性價值放大 → agent 的輸出品質高度依賴 context 裡的既有模式。全專案單一方案、單一寫法(連 Riverpod 的手寫/codegen 都要鎖一種),比「各模組用最適合的方案」更重要。人類能忍受的混搭,會讓 agent 兩種風格亂跳。

最後拿一個具體頁面把樹走一遍:看盤頁,K 線圖、自選股清單、下單面板三塊。K 線圖的縮放平移是純 UI 暫態,setState 關在 widget 裡,誰都不用知道;自選股清單是跨元件共享的即時串流,Riverpod StreamProvider + select 投影,一格報價跳動不牽連整張清單;下單流程碰錢、轉移嚴格(確認→送出→部分成交→撤單)且要留審計軌跡,這是決策樹第 3 條的教科書場景——整個專案唯一的 Bloc,附一段書面理由躺在 README。主幹 Riverpod、例外 Bloc、暫態 setState,三層各司其職:這不是混搭,是分層。

我的 demo 最後選了什麼

講了四天的選型,最誠實的作法是把自己的答案攤開。Waypoint Air 的 pubspec.yaml 執行時依賴只有五個,跟狀態管理有關的就一行:

dependencies:
  flutter_riverpod: ^3.3.2
  go_router: ^17.3.0
  google_fonts: ^8.2.1
  lucide_icons_flutter: ^3.1.15
  cupertino_icons: ^1.0.8

沒有 provider、沒有 flutter_bloc、沒有 equatable。也就是說,我在前面幾天教的 provider(Day 8)和 Bloc(Day 10、Day 17),自己一行都沒用在正式的移植上。

這件事值得說清楚,因為它有兩層意思。

第一層是誠實:那三天的 code 都是我為了理解演進脈絡另外寫的最小範例,不是從 repo 挖出來的實戰經驗。你可以用它們建立心智模型,但不要把它們當成「我踩過的坑」——我踩的坑在 Riverpod 這一側。

第二層才是重點:這個選擇本身就是決策樹第 2 條的實證。我是一個人、寫一支中型 side project、從 Vue 端移植過來,三個條件全部指向 Riverpod。而選完之後回頭看,Day 16 那張對照表就是我當初真正用的翻譯字典——defineStoreNotifierProvidercomputedProvideruseFetchFutureProvider,一格一格對,比讀 Riverpod 官方文件快得多。

至於 Bloc:如果這支 App 真的要收錢、要留審計軌跡,下單那一段我會照決策樹第 3 條走 Bloc。它沒有出現在 pubspec.yaml 裡,不是因為它不好,是因為我的專案還沒有值得它出場的問題。

差異與坑

坑一:三分天下的考古稅。 接手 Flutter 專案,先查 pubspec.yaml 信哪派、哪個版本(Riverpod 1→2、Bloc 7→8 都是破壞性升級)。Vue 人沒繳過這種稅,估工時記得加上去。我的 30 秒判讀順序:見 flutter_bloc + equatable 是 Bloc 派;見 hooks_riverpodriverpod_annotation 是 Riverpod 派(後者代表 codegen 寫法,還要再查 build_runner);只有 provider 的多半是老專案或極簡派,升級路線通常往 Riverpod 走。三個都在?先做好心理準備,再翻 git log 考古是誰在哪一年各自為政。症狀:你照著網路教學寫的 provider 用法貼進專案就報錯,因為這個專案用的是 Riverpod 2 而教學是 3,兩者的 Notifier API 不一樣。

坑二:命名地獄。 provider 是套件、Provider 是 Riverpod 的類別、InheritedWidget 教學也滿口 provide——搜尋錯誤訊息時精確帶上套件名,不然 Stack Overflow 會把你導去隔壁派系的答案。症狀:你搜「flutter provider not found」,前三個結果分別在講三個不同的套件,而它們的解法互相矛盾。

坑三:別混三套。 「登入用 Bloc、購物車用 Riverpod、主題用 provider」的專案真實存在,每一塊都有當初的道理,加起來就是災難。選一套當主幹,例外要有書面理由。症狀:新人問「這個新頁面該用哪一套」,團隊裡三個人給出三個答案,而且三個都舉得出專案裡的先例。

坑四:Web 平台的好消息與壞消息。 好消息:這三套全是純 Dart,在 Flutter Web 上行為與 mobile 一致,選型不用考慮平台。壞消息換個位置收:Vue 選 Pinia 時要想 SSR hydration,Flutter Web 根本沒有 SSR 可想——這個「簡化」的代價,模組六(Day 25 起)談 SEO 時會連本帶利討回來。症狀:這一條現在沒有症狀,症狀會在你被問「為什麼 Google 搜不到我們的產品頁」那天出現。

模組四收官,如果只帶走三件事:一、Riverpod 是 Pinia 人的最短遷移路徑,Day 16 的對照表可以直接當翻譯字典用;二、編譯期窮舉(AsyncValue、sealed class)是 Vue 生態沒有的防線,值得為它重訓肌肉記憶;三、agent 時代的選型天平往「樣板重但檢查嚴」的方案傾斜——樣板的稅由 agent 繳,檢查的紅利由你收。

小結與下一篇

一句話:一般專案選 Riverpod(離 Pinia 最近)、嚴格流程選 Bloc(把狀態機交給編譯器)、agent 工作流下一致性大於一切。模組四完結,明天 Day 20〈Vite build 流程與最佳化策略回顧〉進入模組五建置與部署——從心智模型走向實測數據,先回顧 Vite 這把量尺。

參考資料

如果你卡在語法

深入原理


上一篇
Day 18|跨模組狀態共享:Vue provide/inject vs Flutter InheritedWidget
系列文
Vue 前端工程師視角看 Flutter Web19
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言