理解Redux中间件

690 阅读3分钟

这篇文章主要其实是我之前发布的《Redux 源码分析》的补充,这一篇主要来聊一下applyMiddleware ,就是Redux的中间件

Redux调用中间件过程

如何引入中间件

如果我们想在Redux中使用中间件,在创建stores时这么写

import { createStore,applyMiddleware } from 'redux'
let store = createStore( 
  todoApp,
  // ...middleware 代表你要传入的中间件
  applyMiddleware(...middleware)
)

引入中间件时createStore的处理

看下createStore部分的源码最开始部分,

 //reducer是传入的reducer,preloadedState是初始化时的state,enhancer就是增强器。
 function createStore(reducer, preloadedState, enhancer) {
      //当你只传了两个参数,而且第二个参数是function就当你传入了增强器
      if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
        enhancer = preloadedState;
        preloadedState = undefined;
      }
      //再判断不是undefined和确定是function后,返回一个传入了createStore返回的函数再传入
      if (typeof enhancer !== 'undefined') {
        if (typeof enhancer !== 'function') {
          throw new Error('Expected the enhancer to be a function.');
        }
        
        //reducer, preloadedState(这里的preloadedState已经在上面赋值undefined了)调用然后return。
        return enhancer(createStore)(reducer, preloadedState);
      }
}

Redux文档没有说enhancer就是applyMiddleware,applyMiddleware只是Redux提供给我们的一个中间件加载器而已,如果有特殊场景我们也可以做一个像applyMiddleware的中间件加载器,就是要按照Redux的规范来写。

比如我们的enhancer就是Redux提供的applyMiddleware,我们接着往下说。

applyMiddleware的处理

function applyMiddleware() {
  //首先applyMiddleware把所有中间件存到middlewares数组
  for (var _len = arguments.length, middlewares = Array(_len), _key = 0; _key < _len; _key++) {
    middlewares[_key] = arguments[_key];
  }
  
  //通过createStore高级函数的处理,applyMiddleware就是个包含createStore函数的闭包。
  //然后传入reducer, preloadedState创建store。
  return function (createStore) {
    return function (reducer, preloadedState, enhancer) {
      var store = createStore(reducer, preloadedState, enhancer);
      var _dispatch = store.dispatch;
      var chain = [];
      
      //声明 middlewareAPI 包含 getState 和 dispatch, dispatch可以调用store的dispatch方法
      var middlewareAPI = {
        getState: store.getState,
        dispatch: function dispatch(action) {
          return _dispatch(action);
        }
      };
      
      //然后用map所有中间件传入middlewareAPI调用,存入chain数组。因此中间件写法首先会获取dispatch, getState两个参数。
      chain = middlewares.map(function (middleware) {
        return middleware(middlewareAPI);
      });
      
      //compose是个递归函数的方法。
      //这里会chain中的函数传入store.dispatch然后递归调用,就是会把上一个中间件的返回值传递给下一个中间件.
      _dispatch = _compose2['default'].apply(undefined, chain)(store.dispatch);
        
      //最后合并 这就是createStore的返回值
      return _extends({}, store, {
        dispatch: _dispatch
      });
    };
  };
}

Redux简单中间件的写法

const midde = function({ dispatch, getState }){
    return function(dispatch){
      	 return function(action){
      	 	//中间间处理
      	 	return dispatch(action)
      	 };
    };
};

Redux-thunk源码分析

上面了解中间件的运行机制,我想我们拿一个简单中间件看看是怎么写的。

没使用Redux-thunk的写法

如果我们写把action写成函数的形式我们要这么写,而且还要传入dispatch

action

function showNotificationWithTimeout(text) {
      dispatch(showNotification('You just logged in.'))
      setTimeout(() => {
        dispatch(hideNotification())
      }, 5000)
}

组件

<button (text)=>{ showNotificationWithTimeout(this.props.dispatch,text)) } ></button>

Redux-thunk中间件能让我们的中间件写成action写成函数的形式调用,然后通过中间件注入dispatch, getState可以让我们处理。

'use strict';

exports.__esModule = true;
function createThunkMiddleware(extraArgument) {
  return function (_ref) {
    var dispatch = _ref.dispatch,
        getState = _ref.getState;
    return function (next) {
      return function (action) {
        //如果action是function 
        //把参数dispatch, getState, extraArgument 传入action调用
        //如果直接引入Redux-thunk模块,extraArgument默认为undefind,extraArgument是thunk提供可以自定义传递参数的一个参数。
        if (typeof action === 'function') {
          return action(dispatch, getState, extraArgument);
        }
        //不是function就dispatch
        return next(action);
      };
    };
  };
}

var thunk = createThunkMiddleware();
//引用thunk.withExtraArgument就我们就可以传入extraArgument参数
thunk.withExtraArgument = createThunkMiddleware;
exports['default'] = thunk;

现在我们就可以这么写

action

function showNotificationWithTimeout(text) {
  return (dispatch) =>{
      dispatch(showNotification('You just logged in.'))
      setTimeout(() => {
        dispatch(hideNotification())
      }, 5000)
  }
}

组件


const dispatch = { this.props }

<button (text)=>{ dispatch(showNotificationWithTimeout(text)) } ></button>

结束

本人学识尚浅,文章有那么不正确的地方请大家踊跃提出。