博客 / 詳情

返回

不夠“坦誠”的 Zustand:我們是否為了函數式而函數式?

引言

Zustand 是目前 React 生態中最流行的狀態管理庫之一。它以極簡著稱,也是我個人非常喜歡的庫。 但在長期的使用中,我常常產生一種違和感:我們在一個名為“函數式”的庫裏,費力地模擬着面向對象。

那個無處不在的 get()

來看看經典的 Zustand 寫法:

const useStore = create((set, get) => ({
  count: 0,
  inc: () => set({ count: get().count + 1 }),
  actionB: () => {
    // 調用另一個 Action
    get().inc(); 
    // 獲取當前狀態
    const val = get().count;
  }
}))

仔細審視這個 get()

  1. 它就是 this:它的作用就是訪問當前實例的上下文。
  2. 它是“二等公民” :你必須顯式地調用它 get(),而且它打破了 JS 引擎對 this 的自然優化。
  3. 心智負擔:在寫複雜邏輯時,你滿屏都是 get().xxx,這並不比 this.xxx 優雅,反而增加了一層函數調用括號的視覺噪音。

那個黑盒般的 set

set 函數的設計初衷是好的(提供類似 setState 的原子更新),但在複雜場景下,它顯得不夠“坦誠”:

  1. 語義模糊set 隱藏了更新的細節。是合併?是替換?是深拷貝?你必須去查文檔或看源碼才能確定它是 "Auto Merging" 的。
  2. 邏輯斷層:當你想複用一段邏輯(比如 Private Method)時,你發現你很難在 create 的閉包裏優雅地定義私有輔助函數,往往只能寫在外面,破壞了 Store 的內聚性。

為了函數式而函數式?

我們推崇函數式編程(FP),是因為它有 純函數無副作用引用透明 等數學上的美感。

但 Zustand 的 Store 定義是純函數嗎?顯然不是。它是一個包含了狀態(State)和行為(Action)的容器。 在計算機科學中,狀態 + 行為 = 對象(Object)

既然我們本質上是在構建一個對象,為什麼要回避 JS 語言原生提供的、經過幾十年打磨的構建對象的最佳工具——Class

我們為了避嫌 "OOP",發明了一套 (set, get) => ({...}) 的 DSL。這不僅犧牲了 Class 的繼承、屬性訪問器(Getter/Setter)等高級能力,還增加了一層理解成本。

這是否是一種形式上的函數式正確,而非工程上的務實選擇

另一種可能性

如果在 React 狀態管理中,我們不再視 class 為洪水猛獸,而是承認它作為 "Model" 載體的合理性,會發生什麼? 這或許值得我們深思。

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.