摘要:要求通過要求數(shù)據(jù)變更函數(shù)使用裝飾或放在函數(shù)中,目的就是讓狀態(tài)的變更根據(jù)可預測性單向數(shù)據(jù)流。同一份數(shù)據(jù)需要響應到多個視圖,且被多個視圖進行變更需要維護全局狀態(tài),并在他們變動時響應到視圖數(shù)據(jù)流變得復雜,組件本身已經(jīng)無法駕馭。
今天是 520,這是本系列最后一篇文章,主要涵蓋 React 狀態(tài)管理的相關方案。
前幾篇文章在掘金首發(fā)基本石沉大海, 沒什么閱讀量. 可能是文章篇幅太長了?掘金值太低了? 還是錯別字太多了");
所以模仿<<內(nèi)核恐慌>>的口號: "想看的人看,不想看的人就別看"
系列目錄
01 類型檢查
02 組件的組織
03 樣式的管理
04 組件的思維
05 狀態(tài)管理
文章目錄
狀態(tài)管理
你不需要狀態(tài)管理
你不需要復雜的狀態(tài)管理
Redux
Mobx
RxJS
其他狀態(tài)管理方案
擴展閱讀
現(xiàn)在的前端框架,包括 React 的一個核心思想就是數(shù)據(jù)驅動視圖, 即UI = f(state). 這種開發(fā)方式的變化其實得益于 Virtual-DOM, 它使得我們不需要關心瀏覽器底層 DOM 的操作細節(jié),只需關心‘狀態(tài)(state)’和‘狀態(tài)到 UI 的映射關系(f)’. 所以如果你是初學者,不能理解什么是‘數(shù)據(jù)驅動’, 還是不推薦繼續(xù)閱讀文章下面的內(nèi)容。
但是隨著 state 的復雜化, 框架現(xiàn)有的組件化方式很難駕馭 f(視圖的映射關系變得復雜, 難以被表達和維護); 或者相關類型的應用數(shù)據(jù)流本來就比較復雜, 組件之間的交互關系多樣,本來難以使用UI = f(state)這種關系來表達; 或者應用的組件狀態(tài)過于離散,需要統(tǒng)一的治理等等. 我們就有了狀態(tài)管理的需求.
狀態(tài)管理最基礎的解決方式就是分層,也就是說和傳統(tǒng)的 MV* 模式?jīng)]有本質(zhì)區(qū)別, 主流狀態(tài)管理的主要結構基本都是這樣的:
他們基本都包含這些特點:
分離視圖和狀態(tài). 狀態(tài)管理器擅長狀態(tài)管理,所以他們一般會將應用狀態(tài)聚合在一起管理,而視圖退化為貧血視圖(只關注展示),這樣就可以簡化f映射關系, 讓UI = f(state)這個表達式更徹底
約束狀態(tài)的變更。Redux 要求通過dispatch+reducer, mobx 要求數(shù)據(jù)變更函數(shù)使用action裝飾或放在flow函數(shù)中,目的就是讓狀態(tài)的變更根據(jù)可預測性
單向數(shù)據(jù)流。數(shù)據(jù)流總是按照 Store -> View -> Store 這樣的方式流動, 簡化數(shù)據(jù)流
但是, React 的狀態(tài)管理方案太多了,選擇這些方案可能會讓人抓狂,你需要權衡很多東西:
面向對象還是函數(shù)式還是函數(shù)響應式");
單 Store 還是多 Store?
不可變數(shù)據(jù)還是可變數(shù)據(jù)?
寫代碼爽還是后期維護爽");
自由還是約束?
強類型還是弱類型?
范式化數(shù)據(jù)還是非范式化?
React 原生還是第三方");
...
對于大部分簡單的應用和中后臺項目來說是不需要狀態(tài)管理的。說實話這些應用和傳統(tǒng) web 頁面沒什么區(qū)別, 每個頁面都各自獨立,每次打開一個新頁面時拉取最新數(shù)據(jù),增刪改查僅此而已. 對于這些場景 React 的組件狀態(tài)就可以滿足, 沒有必要為了狀態(tài)管理而狀態(tài)管理. 這種各自獨立的‘靜態(tài)’頁面,引入狀態(tài)管理就是過度設計了。
在考慮引入狀態(tài)管理之前考慮一下這些手段是否可以解決你的問題:
是否可以通過抬升 State 來實現(xiàn)組件間通信");
如果跨越的層級太多,數(shù)據(jù)是否可以通過 Context API 來實現(xiàn)共享");
一些全局狀態(tài)是否可以放在 localStorage 或 sessionStorage 中?
數(shù)據(jù)是否可以通過外置的事件訂閱器進行共享");
...
當你的應用有以下場景時,就要開始考慮狀態(tài)管理:
組件之間需要狀態(tài)共享。同一份數(shù)據(jù)需要響應到多個視圖,且被多個視圖進行變更
需要維護全局狀態(tài),并在他們變動時響應到視圖
數(shù)據(jù)流變得復雜,React 組件本身已經(jīng)無法駕馭。例如跨頁面的用戶協(xié)作
需要統(tǒng)一管理應用的狀態(tài)。比如實現(xiàn)持久化,可恢復,可撤銷/重做
...
首先確定是否需要 Redux、Mobx 這些復雜的狀態(tài)管理工具");優(yōu)先選擇這些原生態(tài)的狀態(tài)管理方式。
例如: 簡單的使用 Context API 來做狀態(tài)管理:
最近 hooks 用得比較爽(參考上一篇文章: 組件的思維),我就想配合 Context API 做一個狀態(tài)管理器, 后來發(fā)現(xiàn)早就有人這么干了: unstated-next, 代碼只有 38 行(Hooks+Context),接口非常簡單:
依賴于 hooks 本身靈活的特性,我們可以用它來做很多東西, 僅限于想象力. 例如異步數(shù)據(jù)獲取:
抑或者實現(xiàn) Redux 的核心功能:
總結一下使用 hooks 作為狀態(tài)管理器的優(yōu)點:
極簡。如上
可組合性. hooks 只是普通函數(shù), 可以組合其他 hooks,以及其他Hooks Container. 上一篇文章提到 hooks 寫著寫著很像組件,組件寫著寫著很像 hooks,在用法上組件可以認為是一種"特殊"的 hooks。相比組件, hooks 有更靈活的組合特性
以 react 之名. 基于 Context 實現(xiàn)組件狀態(tài)共享,基于 hooks 實現(xiàn)狀態(tài)管理, 這個方式足夠通用.
hooks 很多靈活的特性足以取代類似 Mobx 這些框架的大部分功能
只是普通的 React 組件,可以在 React inspector 上調(diào)試
強類型
基于Context API更容易實現(xiàn)模塊化(或者分形)
需要注意的地方
沒有外置的狀態(tài). 狀態(tài)在組件內(nèi)部,沒有方法從外部觸發(fā)狀態(tài)變更
缺少約束. 是好處也是壞處, 對于團隊和初學者來說沒有約束會導致風格不統(tǒng)一,無法控制項目熵增。好處是可以自定義自己的約束
性能優(yōu)化. 需要考慮 Context 變更帶來的性能問題
調(diào)試體驗不如 Redux
沒有數(shù)據(jù)鏡像, 不能實現(xiàn)諸如事件管理的需求
沒有 Redux 豐富的生態(tài)
所以 Context+ Hooks 可以用于滿足簡單的狀態(tài)管理需求, 對于復雜的狀態(tài)管理需求還是需要用上 Redux、Mobx 這類專業(yè)的狀態(tài)管理器.
其他類似的方案
unstated unstated-next 的前身,使用 setState API
react-hooks-global-state
擴展
React Context API?—?A Replacement for Redux");
unstated: 可能是簡單狀態(tài)管理工具中最好的
unstated 是一個極簡的狀態(tài)管理方案,其作者也說了不要認為unstated 是一個 Redux killer, 不要在它之上構建復雜的工具,也就是不要重復造輪子。所以一般到了這個地步, 其實你就應該考慮 Redux、Mobx、Rxjs 這些復雜的狀態(tài)管理框架了。
Redux 是學習 React 繞不過的一個框架. 盡管 Redux 的代碼只有一百多行,概念卻很多,學習曲線非常陡峭,看官方文檔就知道了。即使它的實現(xiàn)很簡潔,但是開發(fā)代碼并不簡潔(和 mobx 相反, 臟活留給開發(fā)者),尤其遵循它的"最佳實踐",是從頭開始構建一個項目是非常繁瑣的. 還在現(xiàn)在有類似 dva 或 rematch 這樣的二次封裝庫來簡化它.
本文不打算深入介紹 Redux 的相關實踐, 社區(qū)上面有非常多的教程,官方文檔也非常詳盡. 這里會介紹 Redux 的主要架構和核心思想,以及它的適用場景.
Redux 的主要結構如上,在此之前你先要搞清楚 Redux 的初衷是什么,才能明白它為什么要這么設計. 在我看來 Redux 主要為了解決以下兩個問題:
可預測狀態(tài)
簡化應用數(shù)據(jù)流
其實這也是 flux 的初衷, 只是有些它有些東西沒做好. 明白 Redux 的初衷,現(xiàn)在來看看它的設計就會清晰很多
單一數(shù)據(jù)源 -> 可預測,簡化數(shù)據(jù)流:數(shù)據(jù)只能在一個地方被修改
可以簡化應用數(shù)據(jù)流. 解決傳統(tǒng)多 model 模型數(shù)據(jù)流混亂問題(比如一個 model 可以修改其他 model,一個 view 受到多個 model 驅動),讓數(shù)據(jù)變動變得可預測可調(diào)試
同構化應用開發(fā)
方便調(diào)試
方便做數(shù)據(jù)鏡像. 可以實現(xiàn)撤銷/重做、時間旅行、熱重載、狀態(tài)持久化和恢復
單向數(shù)據(jù)流 -> 簡化數(shù)據(jù)流, 可預測
不能直接修改狀態(tài) -> 可預測
只能通過 dispatch action 來觸發(fā)狀態(tài)變更. action 只是一個簡單的對象, 攜帶事件的類型和 payload
reducer 接收 action 和舊的 state, 規(guī)約生成新的 state. reducer 只是一個純函數(shù),可以嵌套組合子 reducer 對復雜 state 樹進行規(guī)約
不可變數(shù)據(jù).
可測試.
范式化和反范式化. Store 只存儲范式化的數(shù)據(jù),減少數(shù)據(jù)冗余。視圖需要的數(shù)據(jù)通過 reselect 等手段反范式化
通過中間件隔離副作用 -> 可預測 可以說 Redux 的核心概念就是 reducer,然而這是一個純函數(shù)。為了實現(xiàn)復雜的副作用,redux 提供了類似 Koa 的中間件機制,實現(xiàn)各種副作用. 比如異步請求. 除此之外,可以利用中間件機制,實現(xiàn)通用的業(yè)務模式, 減少代碼重復。
Devtool -> 可預測。通過開發(fā)者工具可以可視化數(shù)據(jù)流
什么時候應該使用 Redux");
首先還是警告一下: You Might Not Need Redux, Redux 不是你的第一選擇。
當我們需要處理復雜的應用狀態(tài),且 React 本身無法滿足你時. 比如:
你需要持久化應用狀態(tài), 這樣你可以從本地存儲或服務器返回數(shù)據(jù)中恢復應用
需要實現(xiàn)撤銷重做這些功能
實現(xiàn)跨頁面的用戶協(xié)作
應用狀態(tài)很復雜時
數(shù)據(jù)流比較復雜時
許多不相關的組件需要共享和更新狀態(tài)
外置狀態(tài)
...
最佳實踐
個人覺得react-boilerplate是最符合官方‘最佳實踐’的項目模板. 它的應用工作流如下:
特性:
整合了 Redux 生態(tài)比較流行的方案: immer(不可變數(shù)據(jù)變更),redux-saga(異步數(shù)據(jù)流處理),reselect(選取和映射 state,支持 memo,可復合),connected-react-router(綁定 react-router v4)
根據(jù)頁面分割 saga 和 reducer。見下面
文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://systransis.cn/yun/6902.html
摘要:系列引言最近準備培訓新人為了方便新人較快入手開發(fā)并編寫高質(zhì)量的組件代碼我根據(jù)自己的實踐經(jīng)驗對組件設計的相關實踐和規(guī)范整理了一些文檔將部分章節(jié)分享了出來由于經(jīng)驗有限文章可能會有某些錯誤希望大家指出互相交流由于篇幅太長所以拆分為幾篇文章主要有以 系列引言 最近準備培訓新人, 為了方便新人較快入手 React 開發(fā)并編寫高質(zhì)量的組件代碼, 我根據(jù)自己的實踐經(jīng)驗對React 組件設計的相關實踐...
摘要:前端每周清單半年盤點之與篇前端每周清單專注前端領域內(nèi)容,以對外文資料的搜集為主,幫助開發(fā)者了解一周前端熱點分為新聞熱點開發(fā)教程工程實踐深度閱讀開源項目巔峰人生等欄目。與求同存異近日,宣布將的構建工具由遷移到,引發(fā)了很多開發(fā)者的討論。 前端每周清單半年盤點之 React 與 ReactNative 篇 前端每周清單專注前端領域內(nèi)容,以對外文資料的搜集為主,幫助開發(fā)者了解一周前端熱點;分為...
摘要:一個復雜的應用都是由簡單的應用發(fā)展而來的隨著越來越多的功能加入項目代碼就會變得越來越難以控制本文章主要探討在大型項目中如何對組件進行組織讓項目具備可維護性系列目錄類型檢查組件的組織樣式的管理組件的思維狀態(tài)管理目錄組件設計的基本原則基本原則高 一個復雜的應用都是由簡單的應用發(fā)展而來的, 隨著越來越多的功能加入項目, 代碼就會變得越來越難以控制. 本文章主要探討在大型項目中如何對組件進行組...
摘要:盤點一下,模式反應了典型的控制權問題。異步狀態(tài)管理與控制權提到控制權話題,怎能少得了這樣的狀態(tài)管理工具。狀態(tài)管理中的控制主義和極簡主義了解了異步狀態(tài)中的控制權問題,我們再從全局角度進行分析。 控制權——這個概念在編程中至關重要。比如,輪子封裝層與業(yè)務消費層對于控制權的爭奪,就是一個很有意思的話題。這在 React 世界里也不例外。表面上看,我們當然希望輪子掌控的事情越多越好:因為抽象層...
摘要:盤點一下,模式反應了典型的控制權問題。異步狀態(tài)管理與控制權提到控制權話題,怎能少得了這樣的狀態(tài)管理工具。狀態(tài)管理中的控制主義和極簡主義了解了異步狀態(tài)中的控制權問題,我們再從全局角度進行分析。 控制權——這個概念在編程中至關重要。比如,輪子封裝層與業(yè)務消費層對于控制權的爭奪,就是一個很有意思的話題。這在 React 世界里也不例外。表面上看,我們當然希望輪子掌控的事情越多越好:因為抽象層...
閱讀 2409·2021-11-23 09:51
閱讀 1220·2021-11-22 13:54
閱讀 3432·2021-09-24 10:31
閱讀 1100·2021-08-16 10:46
閱讀 3632·2019-08-30 15:54
閱讀 713·2019-08-30 15:54
閱讀 2896·2019-08-29 17:17
閱讀 3172·2019-08-29 15:08