從零開始寫一個 redux(第四講)

接着上一講的中間件機制繼續講。 上一講中咱們實現了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

爲此咱們決定再構造一箇中間件,命名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 代碼的轉換器,歡迎你們查閱。數組

github.com/mcuking/vue…app

相關文章
相關標籤/搜索