一、前言 #

Reducer 拆分可以使组件获取其最小属性(state),而不需要整个Store。中间件则可以在Action Creator 返回最终可供 dispatch 调用的 action 之前处理各种事情,如异步API调用、日志记录等,是扩展 Redux 功能的一种推荐方式

export default function applyMiddleware(...middlewares) {
  return (createStore) => (reducer, preloadedState, enhancer) => {
    //接收createStore参数
    var store = createStore(reducer, preloadedState, enhancer)
    var dispatch = store.dispatch
    var chain = []

    //传递给中间件的参数
    var middlewareAPI = {
      getState: store.getState,
      dispatch: (action) => dispatch(action)
    }

    //注册中间件调用链
    chain = middlewares.map(middleware => middleware(middlewareAPI))
    dispatch = compose(...chain)(store.dispatch)

    //返回经middlewares增强后的createStore
    return {
      ...store,
      dispatch
    }
  }
}

未应用中间价之前,创建 store 的方式如下

import {createStore} from 'redux';
import reducers from './reducers/index';

export let store = createStore(reducers);

应用中间价之后,创建 store的方式如下

import {createStore,applyMiddleware} from 'redux';
import reducers from './reducers/index';

let createStoreWithMiddleware = applyMiddleware(...middleware)(createStore);
export let store = createStoreWithMiddleware(reducers);

二、为什么要引入middleware #

action ---> dispatcher ---> reducers

如果遇到异步情况,比如点击一个按钮,希望2秒之后更新视图,显示消息“Hi”。我们可能这么写ActionCreator

var asyncSayActionCreator = function (message) {
    setTimeout(function () {
        return {
            type: 'SAY',
            message
        }
    }, 2000)
}

这会报错,因为这个asyncSayActionCreator返回的不是一个action,而是一个function。这个返回值无法被reducer识别

因此,上面那个ActionCreator就可以改写为这样:因为action的返回值是一个函数

var asyncSayActionCreator = function (message) {
    return function (dispatch) {
        setTimeout(function () {
            dispatch({
                type: 'SAY',
                message
            })
        }, 2000)
    }
}

image.png

image.png

三、中间件是如何工作的 #

Middleware的中间件有很多,不过我的这个案例只引用了其中的一个,那就是redux-thunk

export default function thunkMiddleware({ dispatch, getState }) {
  return next => action =>
    typeof action === 'function' ?
      action(dispatch, getState) :
      next(action);
}

意思是如果action是一个函数,执行这个action函数,如果不是函数,执行next函数

四、自定义中间件 #

中间件的签名如下

({ getState, dispatch }) => next => action

根据applyMiddleware 源码,每个中间件接收 getState & dispatch作为参数,并返回一个函数,该函数会被传入下一个中间件的 dispatch 方法,并返回一个接收 action 的新函数

function callTraceMiddleware ({dispatch,getState}){
    return next=> action =>{
        console.trace();
        return next(action);
    }
}
const createStoreWithMiddleware = applyMiddleware(
  thunkMiddleware,
  loggerMiddleware,
  callTraceMiddleware
)(createStore);

reduxmiddleware是对action进行扩展处理,这样丰富了应用需求