002 Redux middleware

11/2/2021 Redux

# 什么是middleware

Redux 中,当action发出之后,reducer立即返回新的state,这个流程是一个同步操作,如果需要异步操作的话就需要使用applyMiddleware并结合一些中间件进行拦截,当我们请求接口后获取了响应数据再将数据交给reducer来修改我们的store数据 foo

本质上就是对 store.dispatch 进行了增强,在发出 Action和执行 Reducer这两步之间,添加了其他功能

一些常见的中间件

  • redux-thunk
  • redux-saga

相关用法详见异步编程

# middleware实现原理

Redux 提供了 applyMiddleware 方法来加载 middleware,该方法的源码如下

import compose from './compose';
export default function applyMiddleware(...middlewares) {
    return (next) => (reducer, initialState) => {
        let store = next(reducer, initialState);
        let dispatch = store.dispatch;
        let chain = [];
        var middlewareAPI = {
            getState: store.getState,
            dispatch: (action) => dispatch(action),
        };
        chain = middlewares.map(middleware => middleware(middlewareAPI));
        dispatch = compose(...chain)(store.dispatch);
        return {
            ...store,
            dispatch,
        };
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

所有中间件被放进了一个数组chain,然后嵌套执行,最后执行store.dispatch。可以看到,中间件内部(middlewareAPI)可以拿到getStatedispatch这两个方法;看一下 redux-thunk 的源码

const thunk = function ({dispatch, getState}) {
  return function (next) {
    return function (action) {
      if (typeof action === 'function') {
        return action(dispatch, getState)
      } else {
        return next(action)
      }
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11

函数式编程思想设计

middleware 的设计有点特殊,是一个层层包裹的匿名函数,这其实是函数式编程中的 currying,它是一种使用匿名单参数函数来实现多参数函数的方法。applyMiddleware 会对 logger 这个 middleware 进行层层调用,动态地将 storenext 参数赋值。

另外, applyMiddleware 的结构也是一个多层 currying 的函数。借助 composeapplyMiddleware 可以用来和其他插件加强 createStore 函数:

import { createStore, applyMiddleware, compose } from 'Redux';
import rootReducer from '../reducers';
import DevTools from '../containers/DevTools';

const finalCreateStore = compose(
  // 在开发环境中使用的 middleware
  applyMiddleware(d1, d2, d3),
  // 它会启动 Redux DevTools
  DevTools.instrument()
)(createStore);
1
2
3
4
5
6
7
8
9
10
Last Updated: 11/3/2021, 6:25:30 PM