接着上一講的中間件機制繼續講。 上一講中咱們實現了redux-thunk中間件,使得加強後的dispatch不只可以接收對象類型的action,還可以接收函數類型的action。 在此咱們是否可以在構造一箇中間件,使得加強後的dispatch還能處理action組成的數組,以下:javascript
export function buyHouse() {
return {type: BUY_House}
}
export function buyHouseAsync() {
return dispatch => {
setTimeout(() => {
dispatch(buyHouse())
}, 2000)
}
}
export function buyTwice() {
return [buyHouse(), buyHouseAsync()]
}
複製代碼
爲此咱們決定再構造一箇中間件,命名redux-arrThunk,使加強後的dispatch還能處理action組成的數組。代碼以下:vue
const arrThunk = ({dispatch, getState}) => next => action => {
// next爲原生的dispatch
// 若是是數組,依次執行數組中每個action,參數是dispatch和getState
if (Array.isArray(action)) {
return action.forEach(v=>dispatch(v))
}
// 若是不知足條件,則直接調用下一個中間件(使用next)
// 若是知足條件,則須要從新dispatch(調用dispatch)
// 默認直接用原生dispatch發出action
return next(action)
}
複製代碼
由於原理相似第三講中的redux-thunk,上面的代碼並不難,但問題是,咱們如何將這兩個中間件疊加起來使用,爲此咱們須要修改以前的applyMiddleware函數,使其可以接收多箇中間件,而且是的這些中間件可以疊加使用。代碼以下:java
// applyMiddleware
export function applyMiddleware(...middlewares) {
return createStore => (...args) => {
// 第一步 得到原生store以及原生dispatch
const store = createStore(...args)
let dispatch = store.dispatch
const midApi = {
getState: store.getState,
dispatch: (...args) => dispatch(...args)
}
// 第二步 將原生dipatch傳入中間件進行擴展加強,生成新的dispatch
const middlewaresChain = middlewares.map(middleware => middleware(midApi))
dispatch = compose(...middlewaresChain)(dispatch)
// dispatch = middleware(midApi)(dispatch)
return {
...store, // 原生store
dispatch, // 加強擴展後的dispatch
}
}
}
// compose
//compose(fn1, fn2, fn3) return爲 fn1(fn2(fn3))
export function compose(...funcs) {
if (funcs.length === 0) {
return arg => arg
}
if (funcs.length === 1) {
return funcs[0]
}
return funcs.reduce((ret, item) => (...args) => ret(item(...args)))
}
複製代碼
對比上一講中的applyMiddleware,這一次主要是在處理中間件時,對中間件進行了遍歷,而且經過compose方法使得多箇中間件能夠疊加使用,即將fn1, fn2, fn3 轉換爲 fn1(fn2(fn3))react
// 以前
dispatch = middleware(midApi)(dispatch)
// 以後
const middlewaresChain = middlewares.map(middleware => middleware(midApi))
dispatch = compose(...middlewaresChain)(dispatch)
複製代碼
所以能夠像以下代碼同樣進行疊加使用多箇中間件git
import React from 'react'
import ReactDOM from 'react-dom'
import { createStore, applyMiddleware } from './mini-redux'
import { Provider } from './mini-react-redux'
import { counter } from './index.redux'
import thunk from './mini-redux-thunk'
import arrThunk from './mini-redux-arrThunk'
import App from './App'
const store = createStore(counter, applyMiddleware(thunk, arrThunk))
ReactDOM.render(
(
<Provider store={store}> <App/> </Provider>
),
document.getElementById('root')
)
複製代碼
其中const store = createStore(counter, applyMiddleware(thunk, arrThunk))
,意味着加強後的dispatch具備以下功能github
dispatch(action) = thunk(arrThunk(midApi)(store.dispatch)(action))
複製代碼
至此,咱們的 mini 版 redux 就開發完成咯,有任何問題或意見歡迎聯繫我。redux
另外最近正在寫一個編譯 Vue 代碼到 React 代碼的轉換器,歡迎你們查閱。數組