redux applyMiddleware源码解析、redux-thunk源码解析、redux-logger源码解析

中间件的思想和koa的洋葱模型类似,当遇到next时交给下一个中间件处理,当最后一个中间件处理完毕后,依次退回到上一个next之后执行
在这里插入图片描述
主要通过reduce将之后的函数作为参数传递给上一个函数,则上一个函数调用参数就会执行下一个函数,在下一个函数执行完后退回

export default function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg
  }

  if (funcs.length === 1) {
    return funcs[0]
  }
	//当传递了多个函数时
  return funcs.reduce((a, b) => (...args) => a(b(...args)))
}
————————————————
  • 若传递的是compose(e,f,g) ,则第一次调用返回(…args) => e(f(…args))
  • 第二次调用,a为(…args) => e(f(…args)),b为g
  • 则最终调用结果为(…args) => e(f(g(…args)))

一个中间件格式示例:

function M1(store) {
  return function(next) {
    return function(action) {
      console.log('A middleware1 开始');
      next(action)
      console.log('B middleware1 结束');
    };
  };
}

applyMiddleware

  • 核心返回通过中间件改造后的dispatch
let store = applyMiddleware(loggerMiddleware)(createStore)(rootReducer);


export default function applyMiddleware(...middlewares) {            
	return (next)  => 
		(reducer, initialState) => {
			  //这里的next为createStore
              var store = next(reducer, initialState);
              var dispatch = store.dispatch;
              var chain = [];

              var middlewareAPI = {
                getState: store.getState,
                dispatch: (action) => dispatch(action)
              };

              chain = middlewares.map(middleware =>
                            middleware(middlewareAPI));
              dispatch = compose(...chain, store.dispatch);
              return {
                ...store,
                dispatch
              };
           };
}
  • chain的作用将store的getState方法、和改造的dispatch传给中间件,并返回第二层函数,chain = [(next)=>(action)=>{…}, (next)=>(action)=>{…}, (next)=>(action)=>{…}]
  • 传递改造后的disptach原因看下面的redux-thunk
  • compose的作用:compose(A, B, C, arg) === A(B(C(arg)))
  • 则最后一个中间件的next是store.dispatch这个操作store的原始方法
  • A的next是B的action方法,B的next是C的action方法,C的next是store.dipatch
  • 又因为A执行后为(action)=>{…},所以添加中间件改造后的dispatch传入的action,能够通过next传递给下一个中间件的(action)=>{…},最终通过最后一个中间件的next即store.dispatch传递给reducer
function M1(store) {
  return function(next) {
    return function(action) {
      console.log('A middleware1 开始');
      next(action)
      console.log('B middleware1 结束');
    };
  };
}

function M2(store) {
  return function(next) {
    return function(action) {
      console.log('C middleware2 开始');
      next(action)
      console.log('D middleware2 结束');
    };
  };
}

function M3(store) {
  return function(next) {
    return function(action) {
      console.log('E middleware3 开始');
      next(action)
      console.log('F middleware3 结束');
    };
  };
}
  
function reducer(state, action) {
  if (action.type === 'MIDDLEWARE_TEST') {
    console.log('======= G =======');  
  }
  return {};
}

react-thunk
基本使用

export const increment=(num)=>({type:INCREMENT,data:num})
//异步action返回函数
export const incrementAsync=(num)=>{return dispatch=>{
    setTimeout(()=>{
        dispatch(increment(num))
    },1000)
}}

...
this.props.incrementAsync(num);
function createThunkMiddleware(extraArgument) {
  return ({ dispatch, getState }) => next => action => {
    if (typeof action === 'function') {
      return action(dispatch, getState, extraArgument);
    }

    return next(action);
  };
}

  • 因为这里使用了react-redux高阶函数this.props.incrementAsync(num)的调用,相当于改造的dispatch(incrementAsync(num))
  • dispatch即为createThunkMiddleware中的action函数,当调用时,因为参数action为一个函数,即
dispatch=>{
    setTimeout(()=>{
        dispatch(increment(num))
    },1000)
}
  • 所以会走action(dispatch, getState, extraArgument)
  • 将改造后的dispatch传递进去,又因为在这里改造后的dispatch就是createThunkMiddleware中的action函数,所以调用时又回去了,不过此时if判断中action不再是一个函数,而是一个{type:…}对象,所以此时会走next(action)交给下一个中间件处理
  • 这也是为什么传递给中间件的dispatch是改造后的dispatch的原因,因为在redux-thunk中会调用一次重新走中间件的流程
  • 因为dispacth接收的参数必须是一个对象,而异步任务并不会立马传递对象给dispatch,redux-thunk的异步处理其实就是将dispach传入函数,当异步任务完成时调用,和同步任务没啥区别,纯属脱了裤子放屁。。。

redux-logger

  • redux-logger建议放在中间件的最后一位是因为最后一位能保证next为store.dispatch而非改造后的dispatch,所以使用store.dispatch更新store能准确快速拿到更新后的state
export default function createLogger({ getState }) {
      return (next) => 
        (action) => {
              const console = window.console;
              const prevState = getState();
              const returnValue = next(action);
              const nextState = getState();
              const actionType = String(action.type);
              const message = `action ${actionType}`;

              console.log(`%c prev state`, `color: #9E9E9E`, prevState);
              console.log(`%c action`, `color: #03A9F4`, action);
              console.log(`%c next state`, `color: #4CAF50`, nextState);
              return returnValue;
    };
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值