redux 的 middleware 是为了增强 dispatch 而出现的

9c456d5d211602e9d742262c2bf45762_r.jpg

设计和实现

  1. // 这是一个简单的打日志中间件
  2. function logger({ getState, dispatch }) {
  3. // next 代表下一个中间件包装过后的 dispatch 方法,action 表示当前接收到的动作
  4. return next => action => {
  5. console.log("before change", action);
  6. // 调用下一个中间件包装的 dispatch
  7. let val = next(action);
  8. console.log("after change", getState(), val);
  9. return val;
  10. };
  11. }
  12. // 使用 logger 中间件,创建一个增强的 store
  13. let createStoreWithMiddleware = Redux.applyMiddleware(logger)(Redux.createStore);
  14. function compose(...funcs: Function[]) {
  15. return funcs.reduce((a, b) => (...args: any) => a(b(...args)));
  16. }
  17. function applyMiddleware(...middlewares) {
  18. // middlewares 为中间件列表,返回一个接受原始 createStore 方法(Redux.createStore)作为参数的函数
  19. return createStore => (...args) => {
  20. // 创建原始的 store
  21. const store = createStore(...args)
  22. // 每个中间件都会被传入 middlewareAPI 对象,作为中间件参数
  23. const middlewareAPI = {
  24. getState: store.getState,
  25. // 在这里 dispatch 使用匿名函数是为了能在 middleware 中调用 compose 的最新的 dispatch(闭包)
  26. dispatch: (...args) => dispatch(...args)
  27. }
  28. // 给每个中间件传入 middlewareAPI 参数
  29. // 中间件的统一模板为 next => action => next(action) 格式
  30. // chain = [(next)=>(action)=>{…}, (next)=>(action)=>{…}, (next)=>(action)=>{…}],
  31. // … 里闭包引用着 dispatch 和 getState
  32. // 组成一个“洋葱式”的大函数,chain的每个函数元素相当于一层洋葱表皮
  33. const chain = middlewares.map(middleware => middleware(middlewareAPI))
  34. // 传入最原始 store.dispatch 方法,作为 compose 二级参数,compose 方法最终返回一个增强的dispatch 方法
  35. dispatch = compose(...chain)(store.dispatch)
  36. return {
  37. ...store,
  38. dispatch // 返回一个增强版的 dispatch
  39. }
  40. }
  41. }

39169826-ce6df33c-47cb-11e8-8939-9484d9049938.png

闭包的使用

  1. const middlewareAPI = {
  2. getState: store.getState,
  3. // 这里使用匿名函数就是为了捕获下面的 1 处已经增强的dispatch
  4. dispatch: (...args) => dispatch(...args)
  5. }
  6. // 1
  7. dispatch = compose(...chain)(store.dispatch);

简化的例子:

  1. const middleware = ({dispatch}) => (next) => (number) => {
  2. console.log("in middleware");
  3. if(number !== 0){
  4. return dispatch(--number);
  5. }
  6. return next(number);
  7. }
  8. function test() {
  9. var dispatch = (number) => {
  10. console.log("original dispatch");
  11. return number;
  12. };
  13. var middlewareAPI = {
  14. dispatch: (number) => {dispatch(number);}
  15. }
  16. dispatch = middleware(middlewareAPI)(dispatch);
  17. return {
  18. dispatch
  19. }
  20. }
  21. var {dispatch} = test();
  22. dispatch(3);
  23. //输出
  24. // "in middleware"
  25. // "in middleware"
  26. // "in middleware"
  27. // "in middleware"
  28. // "original dispatch"
  29. //var middlewareAPI = {
  30. // dispatch
  31. // }
  32. //输出:
  33. // "in middleware"
  34. // "original dispatch"

参考资料

  1. 图解 Redux 中 middleware 的洋葱模型
  2. redux middleware 详解
  3. Redux 从设计到源码
  4. Redux 中间件对闭包的一个巧妙使用
  5. 解读redux工作原理