"Riverpod"
- Riverpod 的 reactive 邊界
頁面用了 Riverpod 卻對某些變化沒反應、或 reactive 行為在特定時機炸掉時使用。Riverpod 的 reactive 保證只覆蓋 provider 圖的內部——排查沿著圖的邊界走:變化在圖上嗎、在哪個容器的圖上、節點還活著嗎。
- StreamProvider 包 repository watch stream — broadcast、初始值、dispose 實作點
repository 要補 Stream 觀測出口、接給 Riverpod 消費時使用。訂閱模型選 broadcast 還是單訂閱、新訂閱者拿不拿得到當下狀態、controller 誰負責關——每個問題各有一個會靜默失效的預設答案。
- 手寫 dispose() 沒有呼叫者 — Notifier 的依賴與清理都歸 build() 管
Notifier 用建構子注入依賴、或手寫 dispose() 釋放 Timer 與訂閱時使用。Notifier 的建構與銷毀都由容器管理——UI 不會呼叫 dispose()、掛在方法上的清理等於沒掛;依賴在 build() 內 ref.watch、清理在 ref.onDispose 註冊。
- 加書後統計不刷新 — ref.watch 觀察的是 provider 圖、不是資料庫
頁面用了 Riverpod 卻在資料寫入後不更新、或發現自己在導航返回點補 loadData()、用 EventBus 事件觸發 reload 時使用。ref.watch 的 reactive 範圍是 provider 圖上的狀態變化;資料庫寫入不在圖上,補償刷新的出現就是這個缺口的訊號。
- 測試全綠、功能失聯:五個 runtime 問題與組裝層的接線缺口
113 張票收尾全綠的版本,實機測試找出五個問題:路由指向佔位頁、provider 佔位 throw、按鈕空 callback,加上兩個平台語意差異。單元測試的 mock override 是正當的測試 seam、同時是遮蔽接線斷裂的來源——記下三層共振的機制、反向追溯設計文件的結果、以及修補時規格層/測試層/發版層的分層落點。
- 1101 行自建測試基礎設施、重構刪掉 82.5% — 過度工程的三種形態
自建測試基礎設施前先問框架的標準做法是什麼:mock 純資料物件、helper 帶並發鎖與記憶體洩漏防護、mock 放進 lib/ 進生產依賴圖,三種形態都在重新發明 Riverpod overrideWith 一行就有的東西。精緻的設計文件不是價值證明——它可以精心規劃一個不需要存在的系統。
- App 永遠卡在載入畫面 — Riverpod 的 provider 是配方、容器才持有狀態
main() 自建 ProviderContainer 對它觸發初始化、UI 跑在 runApp 的 ProviderScope 裡——兩個容器各持一份 provider 狀態、互不相通,UI 監聽的那份永遠停在初始值。Riverpod 的全域 provider 宣告只是配方、狀態屬於容器實例;跨容器操作是靜默的無效操作。
- await 回來的時候、頁面已經關了 — UnmountedRefException 與 16 個不抽象的檢查點
長 async 流程的每個 await 都是一個 gap:等待期間使用者可能離開、Notifier 被 dispose、回來再寫 state 就炸 UnmountedRefException。修法是每個 gap 後檢查 ref.mounted——而且刻意不抽成 helper:明確的檢查點讓 review 看得見哪個 gap 有守。含「評估必跑、可決定不重構」的技術債處置。