多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
[TOC] ## 什么是Redux中间件 ![](https://box.kancloud.cn/6758d11e210483c91115d0f9cd74f62a_800x600.png) 中间件是插入在用户发射`action`动作之后到`reducer`接收到这个动作之前这个时机的处理器,它能完成一些额外的逻辑。 ## 存在中间件时仓库的初始化 平时我们是这么初始化一个有中间件的仓库的 ``` import {createStore,applyMiddleware} from 'redux'; let store = createStore(reducer,{astate:..,bstate:...,...},applyMiddleware(xx,yy,zz)); ``` 其实内部是这样调用的 ``` let store = applyMiddleware(xxx,yyy,...)(createStore)(reducer,{astate:..,bstate:...,...}) ``` emmm,原理是这样的 ``` export default function createStore(reducer, preloadedState, enhancer){ // 增强器 if(enhancer && typeof enhancer === 'function'){ return enhancer(createStore)(reducer,preloadedState) } ... ``` So,我们现在知道了,如果有中间件,会先执行`applyMiddleware`应用中间件这个方法,并且将`createStore`、`reducer`、`preloadedState`传到applyMiddleware这个方法里面,在里面初始化仓库。 ## 创建一个中间件 我们再来看看平时我们是怎么定义一个中间件的 ``` let logger = ({dispatch,getState})=>next=>action=>{ //do shome thing else console.log(1); next(action); console.log(11); //do some thing else agin } ``` 它等价于 ``` let logger = function({dispatch,getState}){ return function(next){ return function(action){ //do shome thing else console.log(1); next(action); console.log(11); //do some thing else agin } } } ``` 其中,`getState` 就是`createStore`初始化一个仓库时原本导出的getState,`action`也还是用户所发射的那个reducer所接受的那个action, 但`dispatch`不再是createStore所导出的那个了,而是经过中间件包装后的dispatch。 另外`next`其实是另外一个中间件,和Koa中的中间件一样我们需要手动调用next来让队列中的中间件一次执行。并且中间件的运行及结果依然遵循**洋葱模型**。 我们来看这样一个栗子,假若我们有两个中间件 ``` //中间件1 let middle1 = function({dispatch,getState}){ return function(next){ return function(action){ //do shome thing else console.log(1); next(action); console.log(11); //do some thing else agin } } } //中间件2 let middle2 = function({dispatch,getState}){ return function(next){ return function(action){ //do shome thing else console.log(2); next(action); console.log(22); //do some thing else agin } } } ``` 然后我们这样初始化仓库时这样注册他们 ``` let store = applyMiddleware(middle2,middle1)(createStore)(reducer); ``` 那么当我们发射一个动作时,比如说 ``` <button onClick={this.props.increment}>+</button> ``` 那么此时就会调用派发,只不过此时的派发方法是经过先经过`middle1`包装后又经过`middle2`包装的方法。它会先执行`middler2`额外添加的一部分代码,然后再执行`middle1`额外添加的一部分代码,然后才会真正的派发,派发完以后又会将`middle1`剩下的代码执行完,最后是`middle2`剩下的代码。 ![](https://box.kancloud.cn/e80cafbb47fa5a1adc36000b21505138_471x327.png) 执行结果会是:先输出1,再输出2,再执行store.dispatch,再输出22,最后输出11 接下来,我们来看这样的模型具体是怎样实现的。 ## applyMiddleware.js 这个方法最后会将原本的`store.dispatch`给替换成**新的dispatch**,这个新的dispatch是则是我们上面所说的经过中间件层层包装后的新的dispatch。 ``` //applyMiddleware.js export default function(...middlewares){ return function(createStore){ return function(reducer,preloadedState){ let store = createStore(reducer,preloadedState); let dispatch; let middlewareAPI = { getState:store.getState ,dispatch:action=>dispatch(action) } middlewares = middlewares.map(middleware(middlewareAPI)); dispatch = compose(...middlewares)(store.dispatch); return {...store,dispatch}; } } } ``` ## compose.js 在`applyMiddleware.js`中我们用到了一个`compose`方法, 这个方法会把中间件串行起来,并且一层包一层,按照`applyMiddleware()`调用时中间件注册的顺序,**先注册的会成为洋葱模型最外面的一层**,后注册的则往里一层,最里面是原本的store.dispatch。 ``` //compose.js export default function(...fns){ return function(...args){ let last = fns.pop(); return fns.reduceRight((val,fn)=>{ return fn(val); },last(...args)); } } //--- --- --- //高逼格版 export default function(...fns){ if(fns.length === 1)return fns[0]; return fns.reduce((a,b)=>(...args)=>a(b(...args))); } ``` 为了便于理解`compose`函数的作用,请看一下以下的例子 ``` function add1(str){ return str+'com'; } function add2(str){ return str+'po'; } function add3(str){ return str+'se!'; } add3(add2(add1('hello,'))); //输出:hello,compose! //以上等价于 let add = compose(add3,add2,add1); add('hello,'); ``` So,上面的`add`其实就是我们的中间件 ![](https://box.kancloud.cn/2cdd8e9b8d774fd94899f46033f2e064_988x581.png) ![](https://box.kancloud.cn/386567186ca5c62acece61d5027d4a7e_518x178.png) ## thunk ``` ... ,thunkIncrement(){ return function(dispatch,getState){ setTimeout(function(){ dispatch({type:types.INCREMENT,payload:1}) },1000); } } ... ``` ``` //处理自定义异步操作的中间件 let thunk = ({dispatch,getState})=>next=>action=>{ //处理函数的 if(typeof action == 'function'){ action(dispatch,getState); //说明是一个异步动作,将dispatch等传给这个异步动作的函数,在异步有结果后再执行派发改变原本状态。 }else{ next(action); //匹配下一个中间件 } }; ``` ## promise ``` ... //1) ,promiseIncrement(){ return new Promise(function(resolve,reject){ setTimeout(function(){ resolve({type:types.INCREMENT,payload:1}); //reject无法处理 },1000) }); } //2) ,payloadIncrement(){ return { type:types.INCREMENT ,payload:new Promise(function(resolve,reject){ setTimeout(function(){ if(Math.random()>.5){ resolve(100); }else{ reject(-100); } },1000) }) } } ... ``` ``` //处理promise的中间件 let promise = ({dispatch,getState})=>next=>action=>{ if(action.then&&typeof action.then === 'function'){ //是一个promise action.then(dispatch); }else if(action.payload&&action.payload.then){ action.payload.then(payload=>dispatch({...action,payload}),payload=>dispatch({...action,payload})); } else{ next(action); } }; ```