Zustand 帶來更好的實時性、更精準的狀態更新管理、以及更集中、更好閱讀的 code。
在前幾天的文章掌握了 Zustand 的基本概念後,實際開發中我們會面臨新的挑戰:如何標準化非同步操作?如何確保團隊使用一致的模式?
在深入模板之前,讓我們快速回顧基本的 Zustand Store
雖然 Zustand 非常簡潔,但在企業級應用中會遇到一些挑戰:
useStore(state => state.property)
模式重複出現因此 DO RE MI SO ~! 這個進階模板採用了三層架構設計,每一層都有明確的職責,以解決以上的問題。
┌─────────────────┐
│ Store Layer │ ← 狀態定義與組合
├─────────────────┤
│ Actions Layer │ ← 業務邏輯與異步操作
├─────────────────┤
│ Types Layer │ ← 類型定義與約束
└─────────────────┘
雖然 JS 在型別上比較模糊,但只要先定義好,就可以在方法的參考上顯示參數有哪些、型別是什麼,進而定義了整個系統的數據結構。雖然看起來簡單,但它為整個模板提供了型別安全的保障。
這是整個模板最創新的部分,它為非同步操作提供了兩種不同層次的抽象,前者使用 makeAction
包裝,可以自己控制內部複雜的邏輯,無論是要用 get
從 store 拿狀態,或是以非同步的 return 值再去做操作都可以。
makeAction
非同步的操作已知狀態只有三種: loading
, resolved
, rejected
,剛好對應到模板裡面的行為。
初始狀態 → 載入中 → 成功/失敗 → 可選重置
↓ ↓ ↓ ↓
idle loading success idle
failed
首先將狀態定義為 loading,等到非同步結束行為回傳值後,再去看是否有成功,然後更新相對應的狀態。
autowrap
那你可能又會說,這段程式還是太長了,跟 Context API 相比,根本沒有比較短。既然已知非同步的操作已知狀態只有三種,那只需要將結果在操作結束時指定即可,在沒有複雜邏輯的情況下, autoWrapper
所做的就是給 resources.getSomeData
,也就是對後端的 API 給包上一層,用以管理前端狀態更新。
autowrap
是最簡潔的方式,適合簡單的 API 調用場景。
這一層負責將所有組件組合起來集中管理,並通過 createSelectors
提供增強的使用體驗,使用的時候只需要 call useTemplateStore
。
在原生 Zustand 中,我們需要這樣使用:
const attribute1 = useStore(state => state.attribute1)
const attribute2 = useStore(state => state.attribute2)
const setAttribute1 = useStore(state => state.setAttribute1)
而 createSelectors
為每個屬性自動生成專用的 hook:
const attribute1 = useTemplateStore.use.attribute1()
const attribute2 = useTemplateStore.use.attribute2()
const setAttribute1 = useTemplateStore.use.setAttribute1()
// 仍然支援原生方式
const attribute1 = useTemplateStore(state => state.attribute1)
因此我們達到前幾天所說的,粒度的決定權在開發者上,因為每個選擇器只訂閱特定的狀態片段。
接著,在主程式或組件中使用,也可以更好掌握目前非同步行為的狀態,以追蹤是否要狀態改變時相對應的前端畫面。
// 假設有一個動作叫 fetchUserData
// 模板會自動創建:
const isLoading = useTemplateStore.use.is.fetchUserData.loading()
const isSuccess = useTemplateStore.use.is.fetchUserData.success()
const isFailed = useTemplateStore.use.is.fetchUserData.failed()
const error = useTemplateStore.use.is.fetchUserData.error()
這裡想要傳達的概念是異步動作狀態是持久的。這意味著成功的操作會保持成功狀態,直到被明確重置,因此狀態的改變時機可以被清楚的定義,無論是單一組件或是跨域的操作,狀態都不會丟失。
一個很實際的情境,比如使用者搜尋了某些關鍵字而觸發非同步搜尋,即便他之後跳轉了頁面,因為搜索結果會保存在全域狀態中,當使用者再回來,搜索結果依然會存在。
這個模板最強大的特性之一是全域狀態的自動同步與響應式更新。無論用戶在應用的哪個頁面進行操作,因為資料都來自同一個 store,相關的狀態變化都會即時反映到所有訂閱該狀態的組件中。
這種全域狀態管理模式特別適合現代 SPA 應用,其中使用者經常在不同頁面間切換,但需要保持一致的數據體驗。模板確保了無論用戶在哪裡進行操作,相關的 UI 元素都能即時響應,提供流暢的用戶體驗。