Redux中间件原理解析

2020-03-08  本文已影响0人  Yezzle

redux项目开发过程中,有时候我们需要自己去编写一些redux中间件, 但是中间件用法法一般都像下面这样子:

export function myMidware ({dispatch, getState}) {
    //  返回一个接收dispatch为参数的函数
    return (dispatch) => (action) => {
        // do something
        return dispatch(action)
    }
}

//使用中间件
const store = createStore(reducer, applyMiddleware(myMidware))

一看到这种套娃的写法,整个人都是懵的。那么接下来我就带着问题给大家理解理解, 为什么中间件函数非要这么写, applyMiddleware究竟做了什么

废话不多说首先来看看applyMiddleware的源码,看看它到底做了啥:

// 首先这个函数接收多个中间件函数,放在middlewares的数组中
export default function applyMiddleware(...middlewares) {
  // 返回一个接受createStore参数的函数, 这个函数执行之后应该返回一个增强版createStore函数
  // (...args) => { ... } 这里可以看成是一个增强版的createStore函数(从createStore源码可以看出)
  return createStore => (...args) => {
    const store = createStore(...args)
    // 这里的dispatch是不希望你在创建中间件的时候调用它
    let dispatch = () => {
      throw new Error(
        'Dispatching while constructing your middleware is not allowed. ' +
          'Other middleware would not be applied to this dispatch.'
      )
    }

    // 把原版store的api构造成对象准备传递给中间件
    const middlewareAPI = {
      getState: store.getState,
      dispatch: (...args) => dispatch(...args) // 个人感觉这里不给用 其实就没必要给到中间件构造函数里面去
    }
    // 把构造好的api对象传递给中间件,让中间件拥有可以访问store的能力
    const chain = middlewares.map(middleware => middleware(middlewareAPI))
    // compose函数可以把多个中间件函数的数组,合成一个中间件函数的形式,然后再执行中间件
    // 并将得到的新的函数 当作新的dispatch函数
    dispatch = compose(...chain)(store.dispatch)
    // 返回一个增强了dispatch函数的store
    return {
      ...store,
      dispatch
    }
  }
}

从上面的代码解读可以看出, applyMiddleware函数,做了已下事情:


看完了源码,接下来就开始理解这个思路了,套娃开始:

首先是applyMiddleware

再来理解中间件函数执行过程

到此我们就已经完全理解了中间件的执行过程及其作用,其实就是返回了一个dispatch增强器函数的函数,得到的增强器函数接收dispatch返回一个新的dispatch 函数,dispatch执行后会返回action,就是这样的逻辑, 这样我们就可以在actiondispatchstore之前,做一些处理。


compose函数正是一个链式调用dispatch增强器的函数,每次执行一个函数都会返回一个增强过的dispatch函数,给下一个中间件, 下面贴一下compose函数的代码, 感兴趣的可以理解一下:

export default function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg
  }

  if (funcs.length === 1) {
    return funcs[0]
  }
  // 这里的args就是dispatch
  return funcs.reduce((a, b) => (...args) => a(b(...args)))
}

传送门

上一篇下一篇

猜你喜欢

热点阅读