redux 的 middleware 是为了增强 dispatch 而出现的
设计和实现
// 这是一个简单的打日志中间件function logger({ getState, dispatch }) {// next 代表下一个中间件包装过后的 dispatch 方法,action 表示当前接收到的动作return next => action => {console.log("before change", action);// 调用下一个中间件包装的 dispatchlet val = next(action);console.log("after change", getState(), val);return val;};}// 使用 logger 中间件,创建一个增强的 storelet createStoreWithMiddleware = Redux.applyMiddleware(logger)(Redux.createStore);function compose(...funcs: Function[]) {return funcs.reduce((a, b) => (...args: any) => a(b(...args)));}function applyMiddleware(...middlewares) {// middlewares 为中间件列表,返回一个接受原始 createStore 方法(Redux.createStore)作为参数的函数return createStore => (...args) => {// 创建原始的 storeconst store = createStore(...args)// 每个中间件都会被传入 middlewareAPI 对象,作为中间件参数const middlewareAPI = {getState: store.getState,// 在这里 dispatch 使用匿名函数是为了能在 middleware 中调用 compose 的最新的 dispatch(闭包)dispatch: (...args) => dispatch(...args)}// 给每个中间件传入 middlewareAPI 参数// 中间件的统一模板为 next => action => next(action) 格式// chain = [(next)=>(action)=>{…}, (next)=>(action)=>{…}, (next)=>(action)=>{…}],// … 里闭包引用着 dispatch 和 getState// 组成一个“洋葱式”的大函数,chain的每个函数元素相当于一层洋葱表皮const chain = middlewares.map(middleware => middleware(middlewareAPI))// 传入最原始 store.dispatch 方法,作为 compose 二级参数,compose 方法最终返回一个增强的dispatch 方法dispatch = compose(...chain)(store.dispatch)return {...store,dispatch // 返回一个增强版的 dispatch}}}
闭包的使用
const middlewareAPI = {getState: store.getState,// 这里使用匿名函数就是为了捕获下面的 1 处已经增强的dispatchdispatch: (...args) => dispatch(...args)}// 1dispatch = compose(...chain)(store.dispatch);
简化的例子:
const middleware = ({dispatch}) => (next) => (number) => {console.log("in middleware");if(number !== 0){return dispatch(--number);}return next(number);}function test() {var dispatch = (number) => {console.log("original dispatch");return number;};var middlewareAPI = {dispatch: (number) => {dispatch(number);}}dispatch = middleware(middlewareAPI)(dispatch);return {dispatch}}var {dispatch} = test();dispatch(3);//输出// "in middleware"// "in middleware"// "in middleware"// "in middleware"// "original dispatch"//var middlewareAPI = {// dispatch// }//输出:// "in middleware"// "original dispatch"
