10

使用方式

const store = applyMiddleware(...middlewares)(createStore)(reducer, initialState)

源码 版本 0.14.0

function applyMiddleware() {
    //1
  for (var _len = arguments.length, middlewares = Array(_len), _key = 0; _key < _len; _key++) {
    middlewares[_key] = arguments[_key];
  }
  //2
  return function (createStore) {
      //3
    return function (reducer, preloadedState, enhancer) {
      //4
      var store = createStore(reducer, preloadedState, enhancer);
      var _dispatch = store.dispatch;
      var chain = [];
      //5
      var middlewareAPI = {
        getState: store.getState,
        dispatch: function dispatch(action) {
          return _dispatch(action);
        }
      };
      chain = middlewares.map(function (middleware) {
        return middleware(middlewareAPI);
      });
      //6
      _dispatch = _compose2['default'].apply(undefined, chain)(store.dispatch);

      return _extends({}, store, {
        dispatch: _dispatch
      });
    };
  };
}

applyMiddleware方法主要是对redux的dispacth方法进行封装

原理

const _dispatch = store.dispatch;
store.dispatch = function (action) {
  console.log('增强功能');
  _dispatch(action);
  console.log('增强功能');
}

原理很简单就是将store的dispatch进行替换,换成一个功能增强了但是具有dispach功能的新函数请输入代码
原理和java设计模式中的 装饰者模式很像,旨在增强功能,但不改变接口

接下来具体分析 applyMiddleware 函数

1. 代码//1

for (var _len = arguments.length, middlewares = Array(_len), _key = 0; _key < _len; _key++) {
    middlewares[_key] = arguments[_key];
}

由于第一个框号(...middlewares)里面的参数可以是多个中间件(m1,m2,m3)这种类型,或者是一个中间件数组
所以这里通过 遍历 js函数的 arguments 属性将所有的参数取出放到 middlewares 数组中

2. 代码//2 //3

applyMiddleware 这个函数其实是一个 柯里化 的函数,
柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,
并且返回接受余下的参数且返回结果的新函数的技术

这里有几个关键字 多个参数 单一参数 返回接受余下参数的函数 返回结果
//举例

function count(a,b,c) {
    return a+b+c;
}
count(1,2,3);

我们看到 count接受多个参数,这里是三个,最后返回了计算结果,接下来把它柯里化

function count(a) {
    return function(b) {
        return function(c) {
            return a+b+c;
        }
    }
}
count(1)(2)(3);

我们看到区别在于 柯里化 后函数只接受一个参数,返回了接受剩余参数的函数,所以要分多次调用

3. //代码4

var store = createStore(reducer, preloadedState, enhancer);
var _dispatch = store.dispatch;
var chain = [];

这里做了三件事情,1 用reducer创建了一个 store,2 var _dispatch = store.dispatch; 将原来的
dispatch方法保存了起来,因为后我们要覆盖 dispach 但又要用到原始的dispatch的功能,所以保存
3 var chain = [];我们的中间件也是一个 柯里化 的函数,这个数组用来保存中间件接受第一个参数
后返回的函数

4. //代码5

var middlewareAPI = {
    getState: store.getState,
    dispatch: function dispatch(action) {
      return _dispatch(action);
    }
};
chain = middlewares.map(function (middleware) {
    return middleware(middlewareAPI);
});

middlewareAPI 对象有两个成员 getState和dispatch,由于这两个成员我们会在中间件里面用到
所以我们要将它们传递给中间件 调用 middlewares.map 方法,middlewares是一个数组,map方法
接受一个函数,这个函数的第一个参数就是 middlewares 数组的成员,我们调用map方法会遍历
middlewares数组,将它的每一个成员传递给 成员处理函数,最终返回了一个由 处理函数返回值
组成的数组,通过以上代码我们就可以在中间件中使用getState,和dispatch这两个方法了

5. //代码6

_dispatch = _compose2['default'].apply(undefined, chain)(store.dispatch);
return _extends({}, store, {
        dispatch: _dispatch
});

这里做的事情就是我们开始的原理中做的事情 将 disatch 增强并且替换掉store中的dispatch,
替换后的dispach中会调用中间件,我们看到返回值_extends 是一个函数,接收store,和增强后
的_dispatch,用来替换自己的 dispatch方法


_ivenj
291 声望16 粉丝

唯大英雄能本色,是真名士自风流