前言:html
終於好好理解了middleware。。。。es6
1.redux middleware提供的是位於 action 被髮起以後,到達 reducer 以前的擴展點。redux
redux經過store.dispatch(atcion),發起一個action給store,store接收後把當前state與action一塊兒傳給reducer,因此middleware作文章的地方就是dispatch,在原生的dispatch執行以前,先進行一些列的操做。api
實現middleware的方法:下面以logger中間件爲例app
1.手動記錄(不可能會使用這種的吧)異步
let action = addTodo('Use Redux') console.log('dispatching', action) store.dispatch(action) console.log('next state', store.getState())
2.封裝dispatch,函數
要發起action的時候,不用 dispatch 而是用 disptchAddLog()。(把這個方法放在store裏面、好像還不錯的樣子)spa
function dispatchAndLog(store, action) { console.log('dispatching', action) store.dispatch(action) console.log('next state', store.getState()) }
3.猴子補丁,code
經過重寫store.dispatch(), (重寫以後,所使用的dispatch(), 已經不是原生的dispatch了,使用多箇中間件,就是不斷改寫前一次生成的dispatch),htm
(注意:原生的dispatch,已經不可能找到,也就是不能單獨使用原始dispatch了)
function(store) { let next = store.dispatch store.dispatch = function dispatchAndLog(action) { console.log('dispatching', action) let result = next(action) console.log('next state', store.getState()) return result } }
4.隱藏猴子補丁,
乍一看好像和猴子補丁沒什麼卻別,但其實它把賦值的給store.dispatch的邏輯放到了中間件函數的外面,須要外面提過一個applyMiddleware輔助函數來完成插值,除此以外,真的沒什麼區別。(原理仍是猴子補丁)
function logger(store) { let next = store.dispatch // 咱們以前的作法: // store.dispatch = function dispatchAndLog(action) { return function dispatchAndLog(action) { console.log('dispatching', action) let result = next(action) console.log('next state', store.getState()) return result } }
多箇中間件 的實現方式:
function applyMiddlewareByMonkeypatching(store, middlewares) { middlewares = middlewares.slice() middlewares.reverse() // 在每個 middleware 中變換 dispatch 方法。 middlewares.forEach(middleware => store.dispatch = middleware(store) ) }
5.移除猴子補丁,
相對隱藏猴子不一樣,把middleware函數裏面 let next = store.dispatch ,放到函數外面 dispatch = middleware(store)(dispatch)
function logger(store) { return function wrapDispatchToAddLogging(next) { return function dispatchAndLog(action) { console.log('dispatching', action) let result = next(action) console.log('next state', store.getState()) return result } } }
看一下多箇中間件實現方式你就知道了,
是否發現:在 return 的 assign 以前, store.dispatch 都是原生的,並無被改變。因此中間件裏面是否可使用store.dispatch調用原生的,(若是有須要的話),然而筆者試着調用了一下,並不行,會不斷的觸發,就是已是該改變以後的了。
// 警告:這只是一種「單純」的實現方式! // 這 *並非* Redux 的 API. function applyMiddleware(store, middlewares) { middlewares = middlewares.slice() middlewares.reverse() let dispatch = store.dispatch middlewares.forEach(middleware => dispatch = middleware(store)(dispatch) ) return Object.assign({}, store, { dispatch }) }
logger中間件換成es6的箭頭函數更好看
const logger = store => next => action => { console.log('dispatching', action) let result = next(action) console.log('next state', store.getState()) return result }
6.redux中是現實方法
這與 Redux 中 applyMiddleware()
的實現已經很接近了,可是有三個重要的不一樣之處:
它只暴露一個 store API 的子集給 middleware:dispatch(action)
和 getState()
。
它用了一個很是巧妙的方式來保證你的 middleware 調用的是 store.dispatch(action)
而不是 next(action)
,從而使這個 action 會在包括當前 middleware 在內的整個 middleware 鏈中被正確的傳遞。這對異步的 middleware 很是有用。
爲了保證你只能應用 middleware 一次,它做用在 createStore()
上而不是 store
自己。所以它的簽名不是 (store, middlewares) => store
, 而是 (...middlewares) => (createStore) => createStore
。
總結:
redux提供了applyMiddleware(), 若是咱們自定義中間件,也就變的很簡單了
function myMiddleware = (store) => (next) => (action) => { console.log('進入了我本身定義的中間件'); let result = next(action); // 執行下一步 // let result = store.dispatch(action); //不調用next,直接使用store.dispatch調用原生。而後是不行的,會陷入dispatch死循環。 return result; }
applyMiddleware會幫咱們執行前面兩層函數。myMiddleware(store)(dispatch)
redux-thunk的實現也是很牛掰
function createThunkMiddleware(extraArgument) { return ({ dispatch, getState }) => next => action => { if (typeof action === 'function') { return action(dispatch, getState, extraArgument); } return next(action); }; } const thunk = createThunkMiddleware(); thunk.withExtraArgument = createThunkMiddleware; export default thunk;