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
簡化後就是, 接受兩個引數dispatch
和 getState
, 返回一個函式,繼續呼叫則會傳入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
實現的功能, 在有非同步請求的時候,應該返回一個函式,比如下面, 這就可以在裡面繼續使用dispatch
和getState
了,真是煞費苦心啊,就為了實現程式碼隔離的時候還能夠使用redux
裡面的dispatch
和getState
來獲取狀態和觸發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
,生成每個中介軟體都需要的dispatch
和getState
, 接著重點來了,遍歷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 來源:簡書 簡書著作權歸作者所有,任何形式的轉載都請聯絡作者獲得授權並註明出處。