一. Redux 中间件
用途:主要用来处理异步数据流;redux中间件的实质是对store的dispatch进行重新包装,修改store.dispatch的默认行为;redux中间件是对redux功能的一种扩展,也是扩展dispatch的唯一标准方式。是基于函数柯里化实现的!!!
二. 函数柯里化
先来看一下函数柯里化,毕竟函数柯里化是实现 Redux 中间件的基础!!!
函数柯里化就是把接收多个参数的函数变换成一个接收单一参数的函数,并且该函数会返回接收余下的参数的函数【当然这个函数内部还可以接着返回下一个函数,直至参数全部消耗完毕】
栗子1: 比如我们要实现一个求和函数 sum(x,y,z,q) ,它接收四个参数!!
function sum(x,y,z,q){
return x+y+z+q;
}
sum(1,2,3,4);//得到10
那么该 sum 函数经过柯里化后就会变为:
function sum(x){
return function(y){
return function(z){
return function(q){
return x + y + z + q;
}
}
}
}
sum(1)(2)(3)(4) //10
如果采用 ES6 中的箭头函数进行柯里化:
let sum = (x)=>(y)=>(z)=>(q)=>(x+y+z+q);
二. 分析 Redux 中间件的实现
- 假如我们需要在
store.dispatch前后需要查看对应的action以及state,我们需要这么实现:
let action = addTodo('learning redux middlewares');
console.log('dispatched action: ', action);
store.dispacth(action);
console.log('nextState: ', store.getState());
- 如果上述功能是为了我们方便查看日志,显然将其封装为一个函数更方便:
function dispatchAndLog(store, action) {
console.log('dispatched action: ', action);
store.dispacth(action);
console.log('nextState: ', store.getState());
}
- 是方便了一点,但是我们每次使用都需要我们手动去引入该函数;如果我想更方便一点呢?如果我想调用原生的 store.dispatch() 就可以实现这些功能呢?【即对原生的 dispatch() 进行重新包装】
const next = store.dispatch;
store.dispatch = function (action) {
console.log('dispatched action: ', action);
let result = next(action);
console.log('next state: ', store.getState());
return result;
}
- 继续优化【
store.dispatch()函数接受一个action参数,返回同一个dispacthed action】
function dispatchAndLogWrapper (store) {
const next = store.dispatch;
return function dispatchAndLog(action) {
console.log('dispatched action: ', action);
let result = next(action);
console.log('nextState: ', store.getState());
return result;
}
}
- 使其柯里化 === > 可描述为
({ getState, dispatch }) => next => action;
const dispatchAndLogWrapper = store => next => action => {
console.log('dispatch: ', action);
let result = next(action);
console.log('next state: ', store.getState())
return result;
}
【此时,其实我们调用到 dispatchAndLogWrapper(store)(dispatch) 就已经实现了对原生 store.dispatch() 的重新包装】
三. applyMiddleware 的实现
applyMiddleware就是配置 Redux 中间件的函数。【即它所接收的各个中间件都会被依次执行,对原生的store.dispatch()进行包装!!!】会返回最终重新包装完成后的store.dispatch()。
其实现原理如下:
function applyMiddleware(store, middlewares) {
middlewares = middlewares.slice()
middlewares.reverse()
let dispatch = store.dispatch
middlewares.forEach(middleware =>
dispatch = middleware(store)(dispatch)
)
return Object.assign({}, store, { dispatch })
}