redux 源码解读-applyMiddleware

hello,大家好,之前我们大概分析了一下createStore中的代码,但应该还是有很多迷迷糊糊的,感觉不知所以。毕竟这个redux中有很多的牵扯,所以当你把整个redux源码都看了一遍,就会大概的了解redux的原理
下面我们来分析一下applyMiddleware 
export default function applyMiddleware(...middlewares) { // 传入中间件的数组
  return (createStore) => (reducer, preloadedState, enhancer) => { 返回一个函数
    const store = createStore(reducer, preloadedState, enhancer) // 创建store
    let dispatch = store.dispatch // 获得store的dispatch
    let chain = [] // 声明空数组 用来存储action增强函数

    const middlewareAPI = { // 
      getState: store.getState, // 通过store获取state
      dispatch: (action) => dispatch(action) // dispatch方法
    }
    // 传进来的middlewares 进行遍历 返回新数组
    chain = middlewares.map(middleware => middleware(middlewareAPI)) 
    dispatch = compose(...chain)(store.dispatch) // 使用compose进行柯里化
    // 在使用了middleWare的情况下,这里就是我们createStore的返回值。
    return {
      ...store,
      dispatch
    }
  }

大体代码是做什么的已经用注释讲解了,但是可能大家还是有一点朦朦的。

例如为什么applyMiddleware这个函数 又返回了一个多重箭头函数, 为什么disaptch这样就能增强action

这个就会牵扯到我们上一篇讲的createStore

const enhancer = compose(
  applyMiddleware(...middlewares)
);
const store = createStore(
  combineReducers({ ...reducers }),
  initialState,
  enhancer
);

这里的enhancer 等价于 applyMiddleware(...middlewares)

在createStore中传入enhancer 和 applyMiddleware(...middlewares)效果是一样的。

所以相当于applyMiddleware(...middlewares)这个就是createStore传入的 enhancer,在createStore中enhancer要求是一个函数,

现在我们看看applyMiddleware(...middlewares)的返回结果,这里返回了一个函数。

if (typeof enhancer !== 'undefined') {
  if (typeof enhancer !== 'function') {
    throw new Error('Expected the enhancer to be a function.')
  }

  return enhancer(createStore)(reducer, preloadedState)
}

从上面的代码我们可以看到我们首先将createStore传入 applyMiddleware(...middlewares)返回的函数中,然后在将state和reducer传入到enhancer(createStore)返回的函数中。

这样我们就可以知道在我们传入中间件的情况下

const store = createStore(reducer, preloadedState, enhancer) // 创建store

这一行代码才是创建store执行者。

然后我们通过创建的store或者state 和 dispatch 然后创建了一个middlewareAPI 并将其传入middleware中,

这是为了让中间件可以直接和store来进行沟通。

接下来的两行代码可以说是applyMiddleware中最核心的代码了

chain = middlewares.map(middleware => middleware(middlewareAPI))

首先通过map将其遍历 执行中间件。

我们用一下redux-thunk的源码来进行对应的讲解

redux-thunk源码:

function createThunkMiddleware(extraArgument) {
  return ({ dispatch, getState }) => next => action => {
    if (typeof action === 'function') {
      return action(dispatch, getState, extraArgument);
    }

    return next(action);
  };
}

const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;

export default thunk;

这里获得的thunk 是createThunkMiddleware的执行结果  thunk相当于 

 ({ dispatch, getState }) => next => action => {
  if (typeof action === 'function') {
    return action(dispatch, getState, extraArgument);
  }

  return next(action);
};

当我们只有middleWare中只有一个thunk的时候

这时候我们applyMiddleware中的 middlerwares  = [ thunk ] 

chain = middlewares.map(middleware => middleware(middlewareAPI))

就相当于 chain  = middlewares.map(thunk = thunk(middlewareAPI));

执行结果: chain = [ thunk() ]

关于thunk多重箭头函数中的next 和 action 是从哪里来的呢? 

具体是由于下面这一句代码的执行,所引起的

dispatch = compose(...chain)(store.dispatch)

export default 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)))
}

以上是compose的源码

我们看一下里面最核心的就是最后一句代码

return funcs.reduce((a, b) => (...args) => a(b(...args)))

这里使用了reduce操作,我们假设传进去的数组里面有3个中间件A,B,C,然这执行后返回的结果为(..args)=>A(B(C(...args))) 这样一个函数。

然后我们在看看dispatch = compose(...chain)(store.dispatch) 这一行,我们将store.dispatch 传递了进去,所以我们 上面的

(..args)=>A(B(C(...args)))    =>  (store.dispatch) => A(B(C(store.dispatch)));

我们这时候可以看看thunk中间件代码,然后结合上面推出来的表达式,我们能看到如果是最后一个中间件,那么他的next是store.dispatch,如果不是最后一个,那么他的next就是 后一个函数的执行结构。

我们可以推断出来 (store.dispatch) => A(B(C(store.dispatch))) 这一行的返回结果是

以thunk代码为例: 我们执行后会返回这样一个箭头函数。 我们下文将这个箭头函数简称为Action函数

action => {
  if (typeof action === 'function') {
    return action(dispatch, getState, extraArgument);
  }

  return next(action);
};

所以不管有多少个中间件我 compose(...chain)(store.dispatch) 这里返回的一定是Action函数,

然后把这个赋值给dispatch,这个dispatch就是我们正常使用的dispatch函数。

我们在使用redux的时候会调用dispatch这个方法 eg: disptach(action) ; 

在我们调用的时候我们将action传递进去,然后传递到 compose(...chain)(store.dispatch) 返回的函数,执行函数体,然后我们最后返回next(action) 这里的next指向下一个中间件的 Action函数,直到最后面指向store.dispatch;

现在基本解释完了,我们接下来看源码 最后返回了一个对象里面返回了创建的store对象,和增强后的dispatch方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值