# applyMiddleware 实现

在这里看源代码 (opens new window)

使用包含自定义功能的 middleware(中间件) 来扩展 Redux 是一种推荐的方式

# 如何使用

let createStoreWithMiddleware = applyMiddleware(
  reduxThunk,
  logger,
)(createStore);
let store = createStoreWithMiddleware(reducer);
1
2
3
4
5

可以看到 我们传入中间件,createStore,返回的好像重写的 createStore。其实重写的不是 createStore,而是 dispatch。

# applyMiddleware 代码

function compose(...funcs) {
  //如果没有中间件
  if (funcs.length === 0) {
    return (arg) => arg;
  }
  //中间件长度为1
  if (funcs.length === 1) {
    return funcs[0];
  }

  return funcs.reduce((prev, current) => (...args) => prev(current(...args)));
}
const applyMiddleware = (...middlewares) => (createStore) => (...args) => {
  let store = createStore(...args);
  let dispatch;
  const middlewareAPI = {
    getState: store.getState,
    dispatch: (...args) => dispatch(...args),
  };
  //将 getState,dispatch 传给middleware
  let middles = middlewares.map((middleware) => middleware(middlewareAPI));
  dispatch = compose(...middles)(store.dispatch);
  return {
    ...store,
    dispatch,
  };
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

这里是重写 dispatch 但是如何重写的让我先看 middleware 如何实现的

# logger

const logger = (store) => (next) => (action) => {
  if (typeof action !== "function") {
    console.log("dispatching", action);
  }
  let result = next(action);
  console.log("next state", store.getState());
  return result;
};

/**为了好演示 我们把每个函数起个名字**/

// fn1 = next => action => {...}
// fn2 = action => {...}
1
2
3
4
5
6
7
8
9
10
11
12
13

applyMiddleware 中的 middles = [fn1,fn1,fn1],一个 fn1 函数的数组

# compose(...middles)得到的是什么?

compose 饶,但是不复杂可以自己打断看

compose(...middles)得到的是这么一个函数

function(...args){
    return fn1(fn1(fn1(...args)))
}
1
2
3

这个 fn1 是数组由左到右,对应着函数 又外到内.

# compose(...middles)(store.dispatch) 得到的是什么?

dispatch = fn1(fn1(fn1(dispatch))); //这个返回值是什么?
1

此时dispatch 就变成了

function (action){
    //...
        next(action)
        //此时的next 就是上面的fn2
    //...
}
1
2
3
4
5
6

可以理解成 从右到左 每个 fn2 都是 一个包裹的 dispatch,然后当成参数传给它左边的函数。

至此,中间件 结束

# combineReducers

这个实现不复杂直接贴代码好了

function combineReducers(reducers) {
  return function combination(state = {}, action) {
    let nextState = {};
    let hasChanged = false; //状态是否改变
    for (let key in reducers) {
      const previousStateForKey = state[key];
      const nextStateForKey = reducers[key](previousStateForKey, action);
      nextState[key] = nextStateForKey;
      //只有所有的 nextStateForKey 均与 previousStateForKey 相等时,hasChanged 的值才是 false
      hasChanged = hasChanged || nextStateForKey !== previousStateForKey;
    }
    //state 没有改变时,返回原对象
    return hasChanged ? nextState : state;
  };
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15