理解Redux中介軟體

西瓜弟弟發表於2019-03-03

這篇文章主要其實是我之前釋出的《Redux 原始碼分析》的補充,這一篇主要來聊一下applyMiddleware ,就是Redux的中介軟體

Redux呼叫中介軟體過程

如何引入中介軟體

如果我們想在Redux中使用中介軟體,在建立stores時這麼寫

import { createStore,applyMiddleware } from `redux`
let store = createStore( 
  todoApp,
  // ...middleware 代表你要傳入的中介軟體
  applyMiddleware(...middleware)
)
複製程式碼

引入中介軟體時createStore的處理

看下createStore部分的原始碼最開始部分,

 //reducer是傳入的reducer,preloadedState是初始化時的state,enhancer就是增強器。
 function createStore(reducer, preloadedState, enhancer) {
      //當你只傳了兩個引數,而且第二個引數是function就當你傳入了增強器
      if (typeof preloadedState === `function` && typeof enhancer === `undefined`) {
        enhancer = preloadedState;
        preloadedState = undefined;
      }
      //再判斷不是undefined和確定是function後,返回一個傳入了createStore返回的函式再傳入
      if (typeof enhancer !== `undefined`) {
        if (typeof enhancer !== `function`) {
          throw new Error(`Expected the enhancer to be a function.`);
        }
        
        //reducer, preloadedState(這裡的preloadedState已經在上面賦值undefined了)呼叫然後return。
        return enhancer(createStore)(reducer, preloadedState);
      }
}
複製程式碼

Redux文件沒有說enhancer就是applyMiddleware,applyMiddleware只是Redux提供給我們的一箇中介軟體載入器而已,如果有特殊場景我們也可以做一個像applyMiddleware的中介軟體載入器,就是要按照Redux的規範來寫。

比如我們的enhancer就是Redux提供的applyMiddleware,我們接著往下說。

applyMiddleware的處理

function applyMiddleware() {
  //首先applyMiddleware把所有中介軟體存到middlewares陣列
  for (var _len = arguments.length, middlewares = Array(_len), _key = 0; _key < _len; _key++) {
    middlewares[_key] = arguments[_key];
  }
  
  //通過createStore高階函式的處理,applyMiddleware就是個包含createStore函式的閉包。
  //然後傳入reducer, preloadedState建立store。
  return function (createStore) {
    return function (reducer, preloadedState, enhancer) {
      var store = createStore(reducer, preloadedState, enhancer);
      var _dispatch = store.dispatch;
      var chain = [];
      
      //宣告 middlewareAPI 包含 getState 和 dispatch, dispatch可以呼叫store的dispatch方法
      var middlewareAPI = {
        getState: store.getState,
        dispatch: function dispatch(action) {
          return _dispatch(action);
        }
      };
      
      //然後用map所有中介軟體傳入middlewareAPI呼叫,存入chain陣列。因此中介軟體寫法首先會獲取dispatch, getState兩個引數。
      chain = middlewares.map(function (middleware) {
        return middleware(middlewareAPI);
      });
      
      //compose是個遞迴函式的方法。
      //這裡會chain中的函式傳入store.dispatch然後遞迴呼叫,就是會把上一個中介軟體的返回值傳遞給下一個中介軟體.
      _dispatch = _compose2[`default`].apply(undefined, chain)(store.dispatch);
        
      //最後合併 這就是createStore的返回值
      return _extends({}, store, {
        dispatch: _dispatch
      });
    };
  };
}
複製程式碼

Redux簡單中介軟體的寫法

const midde = function({ dispatch, getState }){
    return function(dispatch){
      	 return function(action){
      	 	//中間間處理
      	 	return dispatch(action)
      	 };
    };
};
複製程式碼

Redux-thunk原始碼分析

上面瞭解中介軟體的執行機制,我想我們拿一個簡單中介軟體看看是怎麼寫的。

沒使用Redux-thunk的寫法

如果我們寫把action寫成函式的形式我們要這麼寫,而且還要傳入dispatch

action

function showNotificationWithTimeout(text) {
      dispatch(showNotification(`You just logged in.`))
      setTimeout(() => {
        dispatch(hideNotification())
      }, 5000)
}
複製程式碼

元件

<button (text)=>{ showNotificationWithTimeout(this.props.dispatch,text)) } ></button>
複製程式碼

Redux-thunk中介軟體能讓我們的中介軟體寫成action寫成函式的形式呼叫,然後通過中介軟體注入dispatch, getState可以讓我們處理。

`use strict`;

exports.__esModule = true;
function createThunkMiddleware(extraArgument) {
  return function (_ref) {
    var dispatch = _ref.dispatch,
        getState = _ref.getState;
    return function (next) {
      return function (action) {
        //如果action是function 
        //把引數dispatch, getState, extraArgument 傳入action呼叫
        //如果直接引入Redux-thunk模組,extraArgument預設為undefind,extraArgument是thunk提供可以自定義傳遞引數的一個引數。
        if (typeof action === `function`) {
          return action(dispatch, getState, extraArgument);
        }
        //不是function就dispatch
        return next(action);
      };
    };
  };
}

var thunk = createThunkMiddleware();
//引用thunk.withExtraArgument就我們就可以傳入extraArgument引數
thunk.withExtraArgument = createThunkMiddleware;
exports[`default`] = thunk;
複製程式碼

現在我們就可以這麼寫

action

function showNotificationWithTimeout(text) {
  return (dispatch) =>{
      dispatch(showNotification(`You just logged in.`))
      setTimeout(() => {
        dispatch(hideNotification())
      }, 5000)
  }
}
複製程式碼

元件


const dispatch = { this.props }

<button (text)=>{ dispatch(showNotificationWithTimeout(text)) } ></button>
複製程式碼

結束

本人學識尚淺,文章有那麼不正確的地方請大家踴躍提出。

相關文章