Redux applyMiddleware 原理剖析
Redux applyMiddleware 原理剖析
最近在总结最近用的知识,好记性不如烂笔头,所以写出来记录下。
“It provides a third-party extension point between dispatching an action, and the moment it reaches the reducer.” 这是 Dan Abramov 对 middleware 的描述。它提供了一个分类处理 action 的机会。在 middleware 中,你可以检阅每一个流过的 action,挑选出特定类型的 action 进行相应操作,给你 一次改变 action 的机会。
应用 middleware 后 Redux 处理事件的逻辑
我们还是从实际出发,再来看下内部构造:
打印日志中间件
白名单中间件
applyMiddleware中间件的源码非常精炼,大约只有20多行。
export default function applyMiddleware(...middlewares) { return (createStore) => (reducer, preloadedState, enhancer) => { var store = createStore(reducer, preloadedState, enhancer) var dispatch = store.dispatch var chain = [] var middlewareAPI = { getState: store.getState, dispatch: (action) => dispatch(action) } chain = middlewares.map(middleware => middleware(middlewareAPI)) dispatch = compose(...chain)(store.dispatch) return { ...store, dispatch } } }
看懂这段代码,需要提前了解函数式编程compose以及pipe思想,其实就是一个传参数据流,一个从右到左一个从左到右。我们带着问题去看这段代码,为什么我们平时写的时候要传入(store) => (next) => (action)这三个参数?
代码前几行创建了store,createStore后面三个参数是Redux原生createStore方法的标准参数。下面的middlewareAPI其实就是一个精简的store,并且提供了getState和dispach方法。
接下来来看compose,compose顾英文名思中国义即组合函数,将多个函数组合起来串联执行,一个函数的输出作为另一个函数的输入,一旦第一个函数开始执行,过程就会像多米诺骨牌。
let result = compose(f1, f2, f3, f4)(value); ====> let result = f1(f2(f3(f4(value))));
chain = middlewares.map(middleware => middleware(middlewareAPI)) dispatch = compose(...chain)(store.dispatch)
dispatch = compose(...chain)(store.dispatch)
可以变化为:
fnMiddle = fn(middlewareAPI);
dispatch = fnMiddle(store.dispatch)
最后等价于:
dispatch = fn(middlewareAPI)(store.dispatch)
接着: store.dispatch(action) 等价于 fn(middlewareAPI)(store.dispatch)(action) == 对应middleware的三个参数store, next, action。
dispatch = compose(...chain)(store.dispatch) === dispatch= fn1Middle(fn2Middle(store.dispatch))
// fn1Middle = fn1(middlewareAPI)
首先执行的是fn2Middle(store.dispatch),返回结果是如下的一个函数。紧接着fn1Middle( (action) => {} ),这个action函数相当于占据了fn1中next参数的位置。在收到action参数之前呢函数并不会执行。
// fn2Middle(store.dispatch)执行后 (action) => { .... next(action) .... }