1. 程式人生 > >redux中介軟體原理及實現

redux中介軟體原理及實現

最近看跟react相關庫的原始碼,越來越發現裡面中介軟體機制的特別重要,各種類庫都是基於此封裝的功能,比如redux簡單的幾個函式,卻巧妙的實現了中介軟體建立,組合,呼叫,下面就一一分析

先看下面最簡單的redux使用例子

import { createStore, applyMiddleware, compose } from 'redux'
import thunk from 'redux-thunk'
import reducers from './reducer'

const store = createStore(reducers, compose(
    applyMiddleware(thunk),
    window.devToolsExtension ? window.devToolsExtension() : f => f
))

建立中介軟體

我們從最裡面看,這裡的thunk就是個滿足redux的中介軟體實現,開啟原始碼看看,createThunkMiddleware利用函式柯里化的特性快取了三層引數變數,後面呼叫了才暴露出去的,所以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;

thunk簡化後就是, 接受兩個引數dispatchgetState, 返回一個函式,繼續呼叫則會傳入next就是真正的dispatch的, 這裡action一般都是一個物件,比如{type: AUTH_SUCCESS, payload:data}, 就用dispatch(action)去觸發變更元件,但是這個中介軟體判斷了一下action是函式function的時候,會呼叫這個函式,然後把引數傳進去

function thunk ({ dispatch, getState }) {
   return next => actioin => {
      if (typeof action === 'function') {
         return action(dispatch, getState);
      }
      return next(action);
  }
}

那麼action是函式的時候是怎麼樣的呢,這就是reudx-thunk實現的功能, 在有非同步請求的時候,應該返回一個函式,比如下面, 這就可以在裡面繼續使用dispatchgetState了,真是煞費苦心啊,就為了實現程式碼隔離的時候還能夠使用redux裡面的dispatchgetState來獲取狀態和觸發action實現更新元件

export function login({user, pwd}) {
    return (dispatch, getState) => {
        axios.post('/user/login', {user, pwd})
        .then(res=>{
            if (res.status === 200 && res.data.code === 0){
                dispatch(authSuccess(res.data.data))
            } else {
                dispatch(errorMsg(res.data.msg))
            }
        })
    }
}

使用中介軟體

上面搞清楚了中介軟體的建立,那麼怎麼使用呢,這下就要看applyMiddleware這個函數了,程式碼如下,也沒有幾行,可是資訊量很大啊,整體來看又是柯里化來儲存引數,證明如果有中介軟體的話,會傳入createStore,在這裡面構建store,生成每個中介軟體都需要的dispatchgetState, 接著重點來了,遍歷middlewares中介軟體陣列,分別呼叫每個中介軟體一次

export default function applyMiddleware(...middlewares) {
  return (createStore) => (reducer, preloadedState, enhancer) => {
    const store = createStore(reducer, preloadedState, enhancer)
    let dispatch = store.dispatch
    let chain = []
    const middlewareAPI = {
      getState: store.getState,
      dispatch: (action) => dispatch(action)
    }
    chain = middlewares.map(middleware => middleware(middlewareAPI))
    dispatch = compose(...chain)(store.dispatch)
    return {
      ...store,
      dispatch
    }
  }
}
export default function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg
  }
  if (funcs.length === 1) {
    return funcs[0]
  }
  return funcs.reduce((a, b) => (...args) => a(b(...args)))
}

作者:Jason_Zeng 連結:https://www.jianshu.com/p/8c2a37247020 來源:簡書 簡書著作權歸作者所有,任何形式的轉載都請聯絡作者獲得授權並註明出處。