这个函数设计的很巧妙,值得学习:
export default function applyMiddleware(...middlewares) {// 返回一个匿名函数,接收一个 createStore 参数来创建 storereturn createStore => (...args) => {// 这里的 args 就是 reduces ,创建一个storeconst store = createStore(...args)// 默认dispatch,防止你的中间件是初始化时调用let dispatch = () => {throw new Error('Dispatching while constructing your middleware is not allowed. ' +'Other middleware would not be applied to this dispatch.')}const middlewareAPI = {getState: store.getState,dispatch: (...args) => dispatch(...args)}// 中间件的初始化,每个中间件都传入 getState 和 dispatchconst chain = middlewares.map(middleware => middleware(middlewareAPI))// 使用函数 compose,将所有的中间件串接起来(该函数上面有讲)。// 也就是所有的中间件都能拿到 dispatch 函数// 这里会生成一个新的 dispatch 函数,给 middlewareAPI用。dispatch = compose(...chain)(store.dispatch)return {...store,dispatch}}}
源码的代码量很少,但是却实现了所有的 middleware 可以嵌套调用。
其实看到这里还是有很多疑惑,它是怎么实现所有 middleware 嵌套调用的。
这里要结合一个标准的 middle 例子来说明。
来看redux-thunk。这个库的代码也很少,是一个标准的 middle 。
redux-thunk 源码:
function createThunkMiddleware(extraArgument) {return function ({dispatch, getState}) {// {dispatch, getState} 就是 middlewareAPIreturn function (next) {// next 就是 store.dispatch,是通过 compose 传给每个中间件的return function (action) {// 这个函数就我们写 dispatch 调用到的函数,action就是我们的参数。if (typeof action === 'function') {// 如果 action 是个函数,就是我们所说的异步操作,把 dispatch, getState 传入return action(dispatch, getState, extraArgument);}// 否则执行 dispatch 。例: dispatch({type: 'INIT', payload: 'test'})return next(action);};};};}const thunk = createThunkMiddleware();thunk.withExtraArgument = createThunkMiddleware;export default thunk;
redux 使用:
import thunkMiddleware from "redux-thunk";import { applyMiddleware, combineReducers, createStore } from "redux";const remoteActionMiddleware = applyMiddleware(thunkMiddleware)(createStore);// Storeconst stores = remoteActionMiddleware(combineReducers({...reducers}),);
😃😃😃 是不是有点眉目了,顿时代码都变得清秀了。。。
那action是怎样经过所有中间件的呢?
源码是这样的:
return ({ dispatch, getState }) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
};
那 next这个函数返回什么呢,我们知道它其实就是 store.dispatch,这里就要看 createStore.js里面的dispatch了:
function dispatch(action) {
// 其他省略
// 返回当前的action,例: {type: 'INIT'} 或 是个异步函数
return action
}
嗯,没错store.dispatch返回的就是action。再加上中间件的嵌套,每个中间件都返回 action,然后又可以供下一个next使用。就这样形成了一个完整的链条。
总结
使用
compose来实现中间件的嵌套调用。 返回一个全新的函数,可以接受新的参数(上一个中间件处理过的 dispatch),最终返回一个全新的包含新逻辑的 dispatch 方法。next => action => { // 这里的next就是dispatch return next(action); }将中间件初始化,每个中间件都传入 getState 和 dispatch,并且返回一个新的函数,该函数接收
next作为参数(也就是dispatch)。再返回一下新的dispatch,供下一个middle使用。这样就形成了嵌套调用。
