redux源码分析之五:applyMiddleware

欢迎关注redux源码分析系列文章:
redux源码分析之一:createStore.js
redux源码分析之二:combineReducers.js
redux源码分析之三:bindActionCreators.js
redux源码分析之四:compose.js
redux源码分析之五:applyMiddleware

redux中间件其实非常简单,中间件的目的只有一个:在dispatch前后,执行一些代码,达到增强dispatch的效果,有点类似装饰器的原理。

applyMiddleware需要结合createStore函数来看,appleyMiddleware就是createStore的第三个参数enhancer,比如,对redux-logger中间件,其使用方式如下:

import { applyMiddleware, createStore } from 'redux';
import { createLogger } from 'redux-logger';

const logger = createLogger();
const store = createStore(
  reducer,
  applyMiddleware(logger)
)

applyMiddleware文件的源码如下:

export default function applyMiddleware(...middlewares) {
  return (createStore) => (reducer, preloadedState, enhancer) => {
    const store = createStore(reducer, preloadedState, enhancer)
    let dispatch = store.dispatch
    let chain = []

    const middlewareAPI = {
      getState: store.getState,
      dispatch: (...args) => dispatch(...args)
    }
    chain = middlewares.map(middleware => middleware(middlewareAPI))
    dispatch = compose(...chain)(store.dispatch)

    return {
      ...store,
      dispatch
    }
  }
}

一、applyMiddleware函数的参数

  1. 接受多个参数,每一个参数,都是一个中间件

二、函数的返回值

函数的返回值本身,也是另外一个函数,而这个函数,接受的参数是createStore,结合createStore的前几行源码来看:

export default function createStore(reducer, preloadedState, enhancer) {
  if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
    enhancer = preloadedState
    preloadedState = undefined
  }

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

    return enhancer(createStore)(reducer, preloadedState)
  }
  //其余代码这里忽略
}

可以看到,createStore的第三个参数ehancer如果是一个函数的话,就会优先执行ehancer,然后再再enhancer内部调用createStore函数,所以,createStore其实只会执行一些,也只会生成一个store。

三、关键代码解释

我添加了代码注释如下:(关于compose函数的解释,请参考文章:redux源码分析之四:compose.js):

export default function applyMiddleware(...middlewares) {
  return (createStore) => (reducer, preloadedState, enhancer) => {
    //这里会原封不动的执行createStore,并根据入参生成一个store
    const store = createStore(reducer, preloadedState, enhancer)
    //把dispatch从store中取出来
    let dispatch = store.dispatch
    let chain = []
    
    //这里约定了所有的redux中间件只能使用的api就是2个,getState和dispatch
    const middlewareAPI = {
      getState: store.getState,
      dispatch: (...args) => dispatch(...args)
    }
    对每一个中间件,执行中间件函数,并将中间件api对象传入函数,用chain变量接收中间件执行结果的其返回值
    chain = middlewares.map(middleware => middleware(middlewareAPI))
    //这里用到了compose函数,分别按顺序从后往前执行每一个中间件,并且前一个中间件的返回值作为后一个中间件的入参,所有中间件的第一个入参是原始的store.dispatch
    dispatch = compose(...chain)(store.dispatch)

    //最后返回store对象,只是,使用了经过中间件加工过的dispatch对象,替换掉原始的dispatch对象
    return {
      ...store,
      dispatch
    }
  }
}

四、总结

redux中间件只有一个目的:在dispatch前后,执行一些代码,达到增强dispatch的效果,有点类似装饰器的原理。,理解好了这一点就ok了。
下一篇文章会给大家带来一个最简单的redux中间件,敬请期待。

    原文作者:Happi
    原文地址: https://segmentfault.com/a/1190000016296209
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞