常见的处理异步数据包装流程如下
import rootReducer from '../demo/reducers'

import thunkMiddleWare from 'redux-thunk';
import {loggerMiddleWare} from 'redux-logger';
import { createStore, applyMiddleware } from 'redux'
const store = createStore(
rootReducer,
applyMiddleware(
thunkMiddleWare,
middleWare1,
middleWare2,
...
loggerMiddleWare
)
)
dispatch包装过程解析
- applyMiddleware -- 保存和处理中间件 源码如下
export default function applyMiddleware(...middlewares) {
return createStore => (...args) => {
const store = createStore(...args)
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)
}
const chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
return {
...store,
dispatch
}
}
}
//中间件函数定义模板
const middleWare = ({dispatch, getState}) => next => (action) => {
//中间件处理逻辑
console.log(action)
//中间处理完action后,指向下一个中间件处理
return next(action)
}
applyMiddleware中,middlewareAPI通过闭包会保存新生成增强的dispatch,依次调用中间件传入middleWareAPI,这样每个中间件生成的函数都能够访问新的dispatch,并且生成的函数依次保存在chain中,通过compose(...chain)(store.dispatch)就会生成新的dispatch
- compose(...chain)(store.dispatch)如何增强store.dispatch的
const chain = [f1, f2, f3, ... fn]
//其中函数都是形如以下的函数
fn = next => (action) => {
//中间件逻辑
console.log(action)
//指向下一中间件
return next(action)
}
/**
* compose函数
*/
export default function compose(...funcs) {
if (funcs.length === 0) {
return arg => arg
}
if (funcs.length === 1) {
return funcs[0]
}
return funcs.reduce((a, b) => (...args) => a(b(...args)))
}
compose(...chain)处理后生成如下函数
const generateDispatch = (...args) => {
return f1(f2(f3(f4(...fn(...args)))))
}
当调用f1, f2, f3, ..., fn时,就会生成形如 action => {...}这样的action处理函数,这个action处理函数通过闭包保存了next操作函数
compose(...chain)(store.dispatch)
//相当于执行
generateDispatch(store.dispatch)
这样先调用最后一个fn(store.dispatch),生成一个action处理函数action => {...},这样f1, f2, ... fn-1都会收到后面一个调用返回的action处理函数--这个action函数就是上一个action函数中next函数
比如const actionN = fn-1(action => {...})返回的action处理函数会传参进入fn-2中,成为fn-2返回中的action函数中的next函数。
- Redux Thunk Middleware中间件的作用
function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
};
}
const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;
export default thunk;
上面已经说了每个action都能够获取到新增强的dispatch以及下一个action处理函数--next函数。
applyMiddleware(
thunkMiddleWare,
middleWare1,
middleWare2,
...
loggerMiddleWare
)
thunkMiddleWare中间件作为第一个处理中间件,负责通过判定action类型来进行分发
- 当action是同步数据时,依次调用next函数(中间件生成的action处理函数)处理action,由store.dispatch处理最终的action数据
- 当action是异步数据,此时action是包含异步过程的函数,调用action(dispatch, getState, extraArgument)处理,然后在异步函数中dispatch获取的action数据,然后重复这个处理过程
Redux middleWare总结出的系统扩展模型
- 模型示意图

- 模型说明
原系统
function doSomething(arg) {
// 系统处理
}
中间件定义形式,其中next指向下一个处理插件
var plugin = next => arg => {
// 中间件处理逻辑
pluginDoSomething(arg);
// 继续下个中间件处理
return next(arg);
}
构造中间件处理链
function compose(...chain) {
// 返回一个最终中间件,next将指向原系统api,从而获取扩展的系统
if (chain.length === 0) {
return arg => {
return arg;
}
}
if (chain.length === 1) {
return chain[0];
}
return chain.reduce((a, b) => {
// 箭头函数无绑定的arguments,只能使用函数声明形式
return function() {
return a(b.apply(null, arguments);
}
});
}
扩展后的系统 new_doSomething
var chain = [mid1, mid2, mid3, ...];
var new_doSomething = compose(...chain)(doSomething);