再学习redux的过程中,Middleware这块感觉很烧脑,所以对它的原理进行整理
有一些比较基础的先不整理,
以日志中间件为例
//以下的这种写法属于柯里化的知识
const logger = state => next => action =>{
console.log('dispatch', action);
next(action);
console.log('nextState',store.getState);
}
以上的代码可以解释成
var logger = function logger(state) {
return function (next) {
return function (action) {
console.log('dispatch', action);
next(action);
console.log('nextState', store.getState);
};
};
};
//applyMiddleware 源码
export default function applyMiddleware(...middlewares) {
//假如说 middlewares 里有三个mid1,mid2,mid3
return (createStore) => (reducer, preloadedState, enhancer) => {
const store = createStore(reducer, preloadedState, enhancer)
let dispatch = store.dispatch
let chain = []
//一个保存了store状态,和dispatch方法的对象 这个对应的就是logger 的store
const middlewareAPI = {
getState: store.getState,
dispatch: (action) => dispatch(action)//通过闭包的形式引用外部的dispatch
}
//执行了middleware方法,返回了需要next参数的方法 的数组
chain = middlewares.map(middleware => middleware(middlewareAPI))
//假如chain 为[f1,f2,f3,f4,f5,f6,f7]
//那么下面这句话的翻译就是这样 dispatch = f1(f2(f3(f4(f5(f6(f7(store.dispatch)))))))
//就是将chain中的函数串联到一起,这种组合从最里面开始执行,返回的结果作为上一个函数的参数,一直向外执行
//就是相当于从chain函数的最右侧到最左侧执行
//compose(...chain) 返回的是一个匿名函数 function compose(...funcs) funcs就是chain
//return funcs.reduce((a, b) => (...args) => a(b(...args))) 这里的args就是store.dispatch
dispatch = compose(...chain)(store.dispatch)
//dispatch = f1(f2(f3(f4(f5(f6(f7(store.dispatch)))))))
//当调用dispatch的时候就依次执行
return {
...store,
dispatch// 这个是处理过的dispatch
}
}
}
chain = middlewares.map(middleware => middleware(middlewareAPI))
这里可以看出来,在日志中间件中的第一层的store就是middlewareAPI
并且将第二层返回到chain的数组中
这就相当于当初的store => next => action =>{...}变成了next => action =>{...}
dispatch = compose(...chain)(store.dispatch)
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)))
}
这一步相当于把chain数组中函数,通过处理得到一种类似于层层嵌套的结构f1(f2(f3(f4(args))))
所以dispatch = A(B(C(store.dispatch))
单个中间件较为简单,所以拿三个中间件做例子
经上面所述
//因为抛开store,剩下的中间件的结构类似于下面这种
function A1(next){
return function A2(action){
next(action)
}
}
function B1(next){
return function B2(action){
next(action)
}
}
function C1(next){
return function C2(action){
next(action)
}
}
//dispatch = A(B(C(store.dispatch))
//这种结构会先执行最内部的函数,也就是C(store.dispatch)这一块
//当执行了C 返回的是一个函数
function C2(action){
store.dispatch(action)
}
//返回值最为他的外层函数的参数next
next = function C2(action){
store.dispatch(action)
}
//此时的结构类似于这种
dispatch = A(B(function C2(action) {
store.dispatch(action)
}(action)
)
)
//接下来执行B,返回了
next = function C2(action){
function C2(action){
store.dispatch(action)
}(action)
}
//此时的结构类似于这种
dispatch = A(function B2(action) {
function C2(action){
store.dispatch(action)
}(action)
}(action)
)
//接下来执行A,返回了
dispatch = function A2(action){
function B2(action) {
function C2(action){
store.dispatch(action)
}(action)
}(action)
}(action)
最后返回新的store
总结
- 调用applyMiddleware 传入n个中间件的数组
- 用一个middlewareAPI保存当前的store.getState,和dispatch所指向的函数
- 迭代中间件数组,并执行一遍,将middlewareAPI作为最外层的store,并且返回一个相当于next函数的数组
- 将数组整理成嵌套的函数体,并将store.dispatch传入最内侧的函数的next,并返回经过处理的dispatch (dispatch是一个经过处理的函数,是一个嵌套了多层的函数,其最里面调用的是store.dispatch)
- 返回一个新的store
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。