文章出處

前言:

  終于好好理解了middleware。。。。

1.redux middleware提供的是位于 action 被發起之后,到達 reducer 之前的擴展點。

  redux通過store.dispatch(atcion),發起一個action給store,store接收后把當前state與action一起傳給reducer,所以middleware做文章的地方就是dispatch,在原生的dispatch執行之前,先進行一些列的操作。

 

實現middleware的方法:下面以logger中間件為例

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里面、好像還不錯的樣子)

function dispatchAndLog(store, action) {
  console.log('dispatching', action)
  store.dispatch(action)
  console.log('next state', store.getState())
}

 

3.猴子補丁

  通過重寫store.dispatch(), (重寫之后,所使用的dispatch(), 已經不是原生的dispatch了,使用多個中間件,就是不斷改寫前一次生成的dispatch),

  (注意:原生的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;

 


文章列表


不含病毒。www.avast.com
全站熱搜
創作者介紹
創作者 大師兄 的頭像
大師兄

IT工程師數位筆記本

大師兄 發表在 痞客邦 留言(0) 人氣()