天天看點

Redux三大核心介紹及拓展

什麼是Redux?

  • Redux是JavaScript狀态容器,提供可預測化的狀态管理
  • Redux是由flux演化而來
  • Redux最主要的應用是用作應用狀态的管理

Redux三大核心主要是action、reducer、store

1. action

定義:Action 是把資料從應用傳到 store 的有效載荷。它是 store 資料的唯一來源。一般來說你會通過 store.dispatch() 将 action 傳到 store。

添加新 todo 任務的 action 是這樣的:

Redux三大核心介紹及拓展

action的本質

是 JavaScript 普通對象。我們約定,action 内必須使用一個字元串類型的 type 字段來表示将要執行的動作。多數情況下,type 會被定義成字元串常量。當應用規模越來越大時,建議使用單獨的子產品或檔案來存放 action。

action 建立函數

Action 建立函數 就是生成 action 的方法。“action” 和 “action 建立函數” 這兩個概念很容易混在一起,使用時最好注意區分。

在 Redux 中的 action 建立函數隻是簡單的傳回一個 action:

Redux三大核心介紹及拓展

這樣做将使 action 建立函數更容易被移植和測試。

注意每個 reducer 隻負責管理全局 state 中它負責的一部分。每個 reducer 的 state 參數都不同,分别對應它管理的那部分 state 資料。

2. Reducer

Store 收到 Action 以後,必須給出一個新的 State,這樣 View 才會發生變化。這種 State 的計算過程就叫做 Reducer。

Reducer 是一個純函數,它接受 Action 和目前 State 作為參數,傳回一個新的 State。

Redux三大核心介紹及拓展
Redux三大核心介紹及拓展

純函數

Reducer 函數最重要的特征是,它是一個純函數。也就是說,隻要是同樣的輸入,必定得到同樣的輸出。

純函數是函數式程式設計的概念,必須遵守以下一些限制。

  • 不得改寫參數
  • 不能調用I/O的API
  • 不能調用Date.new()或者Math.random()等不純的方法,因為每次會得到不一樣的結果

由于 Reducer 是純函數,就可以保證同樣的State,必定得到同樣的 View。但也正因為這一點,Reducer 函數裡面不能改變 State,必須傳回一個全新的對象,請參考下面的寫法。

Redux三大核心介紹及拓展

最好把 State 對象設成隻讀。你沒法改變它,要得到新的 State,唯一辦法就是生成一個新對象。這樣的好處是,任何時候,與某個 View 對應的 State 總是一個不變的對象。

Redux的拆分

Redux 提供了 combineReducers() 工具類來做上面 todoApp 做的事情,這樣就能消滅一些樣闆代碼了。有了它,可以這樣重構 todoApp:

Redux三大核心介紹及拓展

注意上面的寫法和下面的完全等價

Redux三大核心介紹及拓展

ES6的使用者注意

combineReducers 接收一個對象,可以把所有頂級的 reducer 放到一個獨立的檔案中,通過 export 暴露出每個 reducer 函數,然後使用 import * as reducers 得到一個以它們名字作為 key 的 object:

Redux三大核心介紹及拓展

3. store

上文,我們學會了使用 action 來描述“發生了什麼”,和使用 reducers 來根據 action 更新 state 的用法。

Store 就是把它們聯系到一起的對象。Store 有以下職責:

  • 維持應用的 state;
  • 提供 getState() 方法擷取 state;
  • 提供 dispatch(action) 方法更新 state;
  • 通過 subscribe(listener) 注冊監聽器;
  • 通過 subscribe(listener) 傳回的函數登出監聽器。

再次強調一下 Redux 應用隻有一個單一的 store。當需要拆分資料處理邏輯時,你應該使用 reducer 組合 而不是建立多個 store。

根據已有的 reducer 來建立 store 是非常容易的。在前一節中,我們使用 combineReducers() 将多個 reducer 合并成為一個。現在我們将其導入,并傳遞 createStore()。

Redux三大核心介紹及拓展

createStore() 的第二個參數是可選的, 用于設定 state 初始狀态。這對開發同構應用時非常有用,伺服器端 redux 應用的 state 結構可以與用戶端保持一緻, 那麼用戶端可以将從網絡接收到的服務端 state 直接用于本地資料初始化。

Redux三大核心介紹及拓展

上面代碼中,window.STATE_FROM_SERVER就是整個應用的狀态初始值。注意,如果提供了這個參數,它會覆寫 Reducer 函數的預設初始值。

Redux總體工作流程

Redux三大核心介紹及拓展

拓展

1. 中間件(middleware)

中間件就是一個函數,對store.dispatch方法進行了改造,在發出 Action 和執行 Reducer 這兩步之間,添加了其他功能。

Redux三大核心介紹及拓展

上面代碼中,redux-logger提供一個生成器createLogger,可以生成日志中間件logger。然後,将它放在applyMiddleware方法之中,傳入createStore方法,就完成了store.dispatch()的功能增強。

這裡有兩點需要注意:

  1. createStore方法可以接受整個應用的初始狀态作為參數,那樣的話,applyMiddleware就是第三個參數了。
    Redux三大核心介紹及拓展
  2. 中間件的次序有講究。
    Redux三大核心介紹及拓展
    上面代碼中,applyMiddleware方法的三個參數,就是三個中間件。有的中間件有次序要求,使用前要查一下文檔。比如,logger就一定要放在最後,否則輸出結果會不正确。

applyMiddlewares是 Redux 的原生方法,作用是将所有中間件組成一個數組,依次執行。所有中間件被放進了一個數組chain,然後嵌套執行,最後執行store.dispatch。

常用中間件

  • redux-logger中間件提供一個生成器createLogger,可以生成日志中間件
  • loggerredux-thunk 中間件改造store.dispatch,使得後者可以接受函數作為參數
  • redux-promise 中間件使得store.dispatch方法可以接受 Promise 對象作為參數

2. React-Redux

目前三大主流架構react、vue、angular都擁有其各自管理應用狀态的手段,其中react我比較推崇使用redux進行管理狀态。

實際上react和redux兩個是完全不相關的,隻是react需要使用到redux來進行自己的應用狀态管理。而在react項目中使用redux,比較好的方式是借助react-redux這個庫來做連接配接。react-redux提供兩個關鍵子產品:connect和provider。

connect

React-Redux 提供connect方法,用于從 UI 元件生成容器元件。connect的意思,就是将這兩種元件連起來。

Redux三大核心介紹及拓展

connect方法接受兩個參數:mapStateToProps和mapDispatchToProps。它們定義了 UI 元件的業務邏輯。前者負責輸入邏輯,即将state映射到 UI 元件的參數(props),後者負責輸出邏輯,即将使用者對 UI 元件的操作映射成 Action。

Redux三大核心介紹及拓展

Provider元件

connect方法生成容器元件以後,需要讓容器元件拿到state對象,才能生成 UI 元件的參數。

一種解決方法是将state對象作為參數,傳入容器元件。但是,這樣做比較麻煩,尤其是容器元件可能在很深的層級,一級級将state傳下去就很麻煩。

React-Redux 提供Provider元件,可以讓容器元件拿到state。

Redux三大核心介紹及拓展

上面代碼中,Provider在根元件外面包了一層,這樣一來,App的所有子元件就預設都可以拿到state了。

總結

三大原則

◇ state以單一對象存儲在store對象中

◇ state是隻讀的,隻有get,沒有set

◇ 使用純函數Reducer執行state更新

state為單一對象,使得redux隻需要維護一顆狀态樹,服務端很容易初始化狀态,易于伺服器渲染。

state隻能通過dispatch(action)來觸發更新,更新邏輯由Reducer來執行。

redux是一個單向資料流的架構,提供可供預測狀态管理

分離了state和props,防止造成混亂

分離了UI和業務邏輯(中間件react-thunk也可以分離出異步資料操作)

自述·Redux