Redux之中间件解读

Store增强器(StoreEnhancer)

createStore函数中有一个enhancer参数,StoreEnhancer类型。enhancer本质其实是一个高阶函数,执行此函数,返回增强后的store

/**
 * @param enhancer store增强器. 你可以选择指定它以增强store的第三方功能,如中间件,时间旅行,持久性等。
 * Redux 附带的唯一存储增强器是“applyMiddleware()”.
 *
 * @returns A Redux store that lets you read the state, dispatch actions
 * and subscribe to changes.
 */
export default function createStore(reducer: Reducer<S, A>,  preloadedState?: PreloadedState<S> | StoreEnhancer,  enhancer?: StoreEnhancer){
  // 如果第二个参数preloadedState是函数类型,并且第三个参数enhancer不存在,就把preloadedState作为增强器。
  if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
    enhancer = preloadedState as StoreEnhancer<Ext, StateExt>
    preloadedState = undefined
  }

  if (typeof enhancer !== 'undefined') {
    if (typeof enhancer !== 'function') {
      throw new Error('Expected the enhancer to be a function.')
    }
    // 执行增强器函数,返回Store,不在执行后续的初始化Store,由增强器内部执行初始化Store的操作。
    return enhancer(createStore)(
      reducer,
      preloadedState as PreloadedState<S>
    ) as Store<ExtendState<S, StateExt>, A, StateExt, Ext> & Ext
  }
}

StoreEnhancer类型,声明方式如下:

const enhancer = createStore => (reducer, preloadedState): Store => {  };

applyMiddleware

applyMiddleware函数的返回值类型则是StoreEnhancer类型,需要返回上述的高阶函数。

  1. 给每个中间件传递参数:getStatedispatch;
  2. 中间件相互组合,形如a(b(c(store.dispatch)),返回新的dispatch;
export default function applyMiddleware(...middlewares: Middleware[]): StoreEnhancer<any> {
  return (createStore: StoreEnhancerStoreCreator) => (
    reducer: Reducer<S, A>,
    preloadedState?: PreloadedState<S>
  ) => {
    const store = createStore(reducer, preloadedState)
    let dispatch: Dispatch = () => {
      throw new Error(
        'Dispatching while constructing your middleware is not allowed. ' +
        'Other middleware would not be applied to this dispatch.'
      )
    }
	// 这里的middlewareAPI.dispatch是传递给中间件的一个参数
	// 当真正调用middlewareAPI.dispatch的时候,会执行内部的dispatch方法,
	// 而此时这个dispatch已经被下面的代码重新赋值,进行了功能增强
    const middlewareAPI: MiddlewareAPI = {
      getState: store.getState,
      dispatch: (action, ...args) => dispatch(action, ...args) 
    }
    // 为每个中间件设置getState和dispatch参数,触发的是中间件外层函数的调用。
    const chain = middlewares.map(middleware => middleware(middlewareAPI))
    // 组合中间件,触发的是中间件第二层函数的调用,入参是下一个中间件第二层函数调用的返回函数,ji。
    dispatch = compose<typeof dispatch>(...chain)(store.dispatch)

    return {
      ...store,
      dispatch
    }
  }
}

compose可以换一种写法

let dispatch = store.dispatch;
chain.reverse().map(dispatchFunc=>{
	dispatch = dispatchFunc(dispatch);
});
return {
	...store,
	dispatch
}

目的是实现形如a( b( c(store.dispatch) ) )的洋葱调用模型

中间件

中间件声明如下:

const middleware = ({getState, dispatch}) => next => action => {
	// TODO
}

如下两个中间件源码都满足上述声明,

redux-thunk中间件

改造store.dispatch,使得dispatch可以接受Function类型的action

function createThunkMiddleware(extraArgument) {
    return ({ dispatch, getState }) => (next) => (action) => {
        if (typeof action === 'function') {
            return action(dispatch, getState, extraArgument);
        }

        return next(action);
    };
}

const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;

export default thunk;
redux-promise源码

改造store.dispatch,使得dispatch可以接受Promise类型的action,或者接受Action 对象的payload属性是一个 Promise 对象。

import isPromise from 'is-promise';
import { isFSA } from 'flux-standard-action';

export default function promiseMiddleware({ dispatch }) {
  return next => action => {
    if (!isFSA(action)) {
      return isPromise(action) ? action.then(dispatch) : next(action);
    }

    return isPromise(action.payload)
      ? action.payload
          .then(result => dispatch({ ...action, payload: result }))
          .catch(error => {
            dispatch({ ...action, payload: error, error: true });
            return Promise.reject(error);
          })
      : next(action);
  };
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青菜小王子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值