大家好,我是卡頌。
在我們React進階源碼羣裏,除了React外,狀態管理是最常討論的話題。
詭異的是,有多個羣友説過類似的話:
他的同事/組長/領導...讓他把所有state都放在Redux/Mobx...裏
他們覺得不對,又不知道如何反駁。
今天我們來聊聊Redux、Mobx等狀態管理庫和React、Vue等視圖庫之間的關係,希望能解決以上困惑。
產品的核心競爭力
如果你在電梯裏遇到大領導,他問你:
小x,你們最近在做什麼功能?
在電梯到達樓層前這短短2分鐘,你該如何向大領導描述你們正在開發的功能呢?
我想你一定會介紹功能的大體邏輯,而不會聊功能裏某個按鈕的具體交互邏輯吧?
你會聊邏輯,而不是交互。因為邏輯是最重要的。
接下來我們通過一個小故事瞭解邏輯與交互的關係。
邏輯與交互的關係
一天,老闆讓你開發文件上傳功能。
開發過程其實就是處理文件上傳這一領域相關的各種狀態之間的關係(比如上傳進度、是否出錯...)。
這部分狀態,我們稱為領域狀態。
邏輯開發完後,你基於各種領域狀態編寫單元測試。
為了快速上線驗證該功能是否有人用,你直接將其作為CLI工具發佈。
幾天後,經過數據驗證,發現功能很受歡迎。於是你選擇React作為視圖庫,基於之前的邏輯開發視圖交互。
開發視圖交互過程中需要處理視圖相關各種狀態(比如loading顯隱、打開關閉狀態...)。
這部分狀態,我們稱為視圖狀態。
可見,一款功能完備的產品包含領域狀態與視圖狀態。前者是必須的,後者是可選的。
視圖庫中的狀態
説回React、Vue這樣的視圖庫。
由於大部分視圖庫以組件作為模塊邊界,所以很自然的,領域狀態與視圖狀態被分割到不同組件中,但他們被分割的方式是完全不同的。
舉個例子,一個完整的應用可以劃分為很多組件:
從視圖狀態角度來看這些組件:
對比上下兩張圖,組件1(黃色與綠色)大小一致,代表這是個交互邏輯自洽的純組件(比如一個開關),他的交互邏輯不依賴其他組件。
除了組件1,更多組件需要與其他組件形成大小互補,這代表他們的交互邏輯互相影響。
比如組件5的長寬受組件2、組件6、組件8影響,可能代表:組件5是個提示框,他是否彈出受2、6、8影響。
我們再從領域狀態(藍色部分)角度來看這些組件:
整個應用的邏輯分散在不同組件中,可能組件1的didMount回調中有一部分邏輯,組件3的useEffect回調中有一部分邏輯。
由於組件5是個提示框,只有提示效果,所以他不包含應用運轉所必需的邏輯(即領域狀態)。
什麼時候使用狀態管理
回到開篇,什麼樣的state(狀態)應該放在狀態管理裏?
對於視圖狀態:
- 狀態自洽的組件自己管理狀態(如組件1)
- 狀態互相之間有影響的組件(如5與2、6、8)根據應用複雜度、組件間跨度決定
如果組件跨度比較近(如是兄弟關係),則公共狀態可以提升到共同父組件。
如果組件跨度較遠且應用不復雜,可以提升到共同的Context中。
如果應用複雜,再考慮狀態管理方案。
對於領域狀態,由於其天生以碎片形式分佈在不同組件中,所以:
- 簡單的小應用可以任其分佈在組件中,或者提升到共同的
Context中 - 其他情況推薦用狀態管理方案
甚至,對於領域狀態中的子領域,可以在有狀態管理方案的基礎上再抽象出來單獨處理。
比如對於服務端請求的數據這一領域狀態,其性質更類似於緩存,在React中可以使用SWR或React Query處理。
總結
本文我們聊了狀態的分類 —— 領域狀態與視圖狀態,對於這兩種狀態根據其特性有不同處理方案。
雖然一股腦將所有狀態都交給Redux處理不是不行,但勢必對項目的可讀性、性能、擴展性造成影響。
學完本文能夠説服同事/組長/領導最好。如果對方執意要Redux一把梭,對待這種執(憨)着(憨)的人,牢記四字箴言: