深入Redux及其中間件

1. Redux簡介

  1. Redux的核心API主要有兩個:createStore和reducer。
  • createStore
    createStore(reducers[, initialState])主要是用于生成store的,reducers必須傳入,initialState是可選擇是否傳入的參數(shù)初始化狀態(tài)。引用時:
    import { createStore } from 'redux'; 
    const store = createStore(reducers);
    
    其中創(chuàng)建的store又包含四個API:
  1. getState():獲取 store 中當前的狀態(tài)。
  2. dispatch(action):分發(fā)一個 action,并返回這個 action,這是唯一能改變 store 中數(shù)據(jù)的方式。
  3. subscribe(listener):注冊一個監(jiān)聽者,它在 store 發(fā)生變化時被調(diào)用。
  4. replaceReducer(nextReducer):更新當前 store 里的 reducer,一般只會在開發(fā)模式中調(diào)用該方法。
  • reducer
    reducer主要負責響應(yīng)action并修改數(shù)據(jù), 它是一個函數(shù),reducer(previousState, action) => newState,需要注意的是第一次執(zhí)行的時候,并沒有任何的 previousState,因此在這種特殊情況下需要返回一個定義好的 initialState。實際運用時:
      const initialState = { 
      todos: [], 
      };
      function todos(previousState = initialState, action) { 
      switch (action.type) {  
        case 'XXX': { 
        // 具體的業(yè)務(wù)邏輯
        } 
        default: 
        return previousState; 
      } 
      }
    
  1. 與React的綁定
    react-redux庫提供了一個組件<Provider/>和一個方法connect()幫助 Redux 和 React 進行綁定。Provider 是整個應(yīng)用最外層的 React 組件,它接受一個 store 作為 props。connect() 可以在整個React應(yīng)用的任意組件中獲取store中的數(shù)據(jù)。

2.Redux中間件

2.1 什么是中間件

傳統(tǒng)的Redux單向數(shù)據(jù)流如圖所示:


Redux單向數(shù)據(jù)流圖

這樣的單向數(shù)據(jù)流動存在很多問題,比如當調(diào)用的action發(fā)生改變時,就必須修改dispatch 或者 reducer,而且請求數(shù)據(jù)不是異步的,因此Redux中間件由此出現(xiàn),它的自由組合,自由插拔的插件機制正好解決了這個問題,它的目的是增強dispatch,Redux運用中間件處理事件的流程如圖所示:


Redux運用中間件處理事件.png

需要注意的是這些中間件會按照指定的順序一次處理傳入的action,只有排在前面的中間件完成任務(wù)之后,后面的中間件才有機會繼續(xù)處理 action。

2.2 中間件機制

Redux是通過applyMiddleware方法來加載中間件的,因此我們首先來看一下applyMiddleware方法的源碼

//compose 可以接受一組函數(shù)參數(shù),從右到左來組合多個函數(shù),然后返回一個組合函數(shù)。
import compose from './compose'; 
export default function applyMiddleware(...middlewares) { 
return (next) => (reducer, initialState) => { 
//為中間件分發(fā)store
let store = next(reducer, initialState); 
let dispatch = store.dispatch; 
let chain = []; 
//將store 的 getState方法和 dispatch 方法賦值給middlewareAPI
var middlewareAPI = { 
getState: store.getState, 
//使用匿名函數(shù),保證最終compose 結(jié)束后的新dispatch保持一致
dispatch: (action) => dispatch(action), 
}; 
//chain: [f1, f2, ... , fx, ..., fn]
chain = middlewares.map(middleware => middleware(middlewareAPI)); 
//利用compose將所有中間件串聯(lián)起來,
dispatch = compose(...chain)(store.dispatch); 
return { 
...store, 
dispatch, 
}; 
} 
}

其中 compose就是將傳入的所有函數(shù)組合成一個新的函數(shù),Redux中的compose實現(xiàn)方式如下所示:

function compose(...funcs) { 
  return arg => funcs.reduceRight((composed, f) => f(composed), arg); 
}

當調(diào)用 reduceRight時依次從 funcs 數(shù)組的右端取一個函數(shù) fn 拿來執(zhí)行,fn的參數(shù) composed 就是前一次 f(n+1) 執(zhí)行的結(jié)果假如n=3,新的 dispatch = f1(f2(f3(store.dispatch))))。
接下來我們看看一個最簡單的中間件是如何實現(xiàn)的:

export default (dispatch, getState) => next => action => next(action)

其中的next是一個函數(shù),當調(diào)用它時,表示一個中間件已經(jīng)完成了任務(wù),然后將這個action傳遞給下一個中間件并作為參數(shù)傳遞給next函數(shù)處理action。
那么使用next(action)和store.dispatch(action)有何區(qū)別呢?簡單的來說store.dispatch(action)都是和新的dispatch一樣的,但是next(action)是進入下一個中間件的操作,所以如果某個中間件使用了store.dispatch(action),就相當于把整個中間件的傳遞過程重頭來一遍。具體如圖所示:

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容