redux中间件详解

418 阅读2分钟

最近在看redux-saga源码,发现它最后也返回标准的Redux中间件格式,之前在解析react-redux中有稍微带到,不过还是有些茫然,现在这部分再梳理下,在这里做个理解。

使用中间件

以日志输出中间件为例

import { applyMiddleware, createStore } from 'redux';
import createLogger from 'redux-logger';
const logger = createLogger();

const store = createStore(
  reducer,
  applyMiddleware(logger)
);

logger 中间件简码

function createLogger(options = {}) {
  
  ····
    
  return store => next => (action) => {
    ·····
    
    let returnedValue;
    returnedValue = next(action);
    return returnedValue;
  };
}

看的出来返回的格式就是 store => next => action =>{} 三层嵌套,接下来我们再把这些拆解下。

applyMiddleware

在之前的文章中,咱们稍微分析了下applyMiddleware,这里再稍微回顾下

1. export default function applyMiddleware(...middlewares) {
2.   return createStore => (...args) => {
3.     // 创建store
4.     const store = createStore(...args)
5.     // 新建变量 dispatch 函数
6.     let dispatch = () => {
7.       throw new Error(
8.         'Dispatching while constructing your middleware is not allowed. ' +
9.           'Other middleware would not be applied to this dispatch.'
10.       )
11.     }
12.     
13.     const middlewareAPI = {
14.       getState: store.getState,
15.       dispatch: (...args) => dispatch(...args)
16.     }
17.     // 把 store.getState 和 dispatch 注入到每个中间件
18.     const chain = middlewares.map(middleware => middleware(middlewareAPI))
19.     // 调用compose, 重新赋值经过中间件扩展后的dispatch
20.     dispatch = compose(...chain)(store.dispatch)
21.     // 返回 store, 扩展后的dispatch
22.     return {
23.       ...store,
24.       dispatch
25.     }
26.   }
27. }

解析三层函数

可以看到从最外层开始看,store就是 middlewareAPI,也就是 getState和 dispatch,

const chain = middlewares.map(middleware => middleware(middlewareAPI))

那么chain就是剩下的两层 next => action =>{},我们看到第20行,

dispatch = compose(...chain)(store.dispatch)

这里chain被当做参数传入compose。compose的作用其实就是循环调用中间件,之前的文章中也较少过,其实效果就是下面一样

const func = [f1, f2, f3];
compose(...func)        //return f1(f2(f3(...args)))
//注意函数调用的顺序是从左到右,即:f1 -> f2 -> f3

这样就能看出其实next 就是 store.dispatch,所以经过层层解析,看到最后返回的就是其实就是被logger包装的dispatch

(action) => {
    let returnedValue = store.dispatch(action); // 这里的next就是store.dispatch
    return returnedValue;
};

这里我们只用了一个中间件,那么大家可以想想一下,多个中间件是什么样子,其实就是循环调用

dispatch = f1(f2(f3(store.dispatch)));

总结

如果没有中间件的话其实我们就是直接调用store.dispatch(action),但是我们需要对action做一些处理或转换,比如异步操作,异步回调后再执行next;这样的设计还是很巧妙,大家有兴趣可以再细细理解下。