在平时的react项目开发中,我们除了会用到redux的基本功能外,还要借助redux的一些中间件(middleware)去完成一些高级的操作,例如使用redux-logger中间件去打印日志,使用redux-thunk去派发一个方法,使用redux-promise去派发一个promise等等。
下面,就让我们一起来看看这几个插件的基本使用,以及实现吧。
首选,我们需要知道redux中间件的一个基本格式,即每一个中间件的基本格式都是如下这样:
function loggerMiddleware({ getState, dispatch }) {
return function (next) {
return function (action) {
};
};
}
注意:中间件内部会有两次返回操作,最外层接收getState,dispatch(store中的dispatch) 参数,其次中间那一层接收 一个next方法(重写的dispatch方法)作为参数,最后一层函数接收本次派发的action对象,有了这个基本的框架认识,那么写出下面几个中间件便不再是难事了。
redux-logger
//getState用来获取仓库状态 dispatch用来重新派发动作
//每一个中间件都会接受到getState,dispatch这两个参数
export default function loggerMiddleware({ getState, dispatch }) {
return function (next) {
//next是为了调用原生的dispatch方法
return function (action) {
//打印派发之前的状态
console.log(`老状态:${JSON.stringify(getState())}`);
//执行派发的动作
next(action);
//打印更新后的状态
console.log(`新状态:${JSON.stringify(getState())}`);
};
};
}
redux-thunk
众所周知,redux在不使用任何中间件的情况下,每次派发的动作action必须是一个纯对象,例如:
add (value){
return { type: 'add', payload: value }
}
所以说如果我们想在派发的过程中去执行一些方法,即派发一个函数,类似于下面的这种效果:
asyncSetName(name) {
//派发一个函数
return (dispatch) => {
//延迟两秒派发动作
delay(2000).then(() => {
dispatch({ type: types.ASYNC_SET_NAME, payload: name });
});
};
}
我们就需要借助到react-thunk的功能,仔细想想,其实这个中间件实现不难,无非就是对派发出来的action做一个检测,实现如下:
export default function thunkMiddleware({ getState, dispatch }) {
return function (next) {
return function (action) {
//如果派发的是一个函数
if (typeof action === "function") {
//直接执行,并且传入dispatch方法
return action(dispatch);
} else {
//如果不是函数,交给下面一个中间件去处理
next(action);
}
};
};
}
redux-promise
redux-promise的作用顾名思义就是派发一个promise对象,可以通过参数resolve来触发action,例子如下:
promiseSetName(dispatch, name) {
return new Promise((resolve, reject) => {
resolve({ type: types.PROMISE_SET_NAME, payload: name });
});
}
有了上面的例子,这个中间件也就依葫芦画瓢了,实现如下:
//检测是不是一个promise
function isPromise(obj) {
return (
!!obj &&
(typeof obj === "object" || typeof obj === "function") &&
typeof obj.then == "function"
);
}
export default function promiseMiddleware({ getState, dispatch }) {
return function (next) {
return function (action) {
// 判断action是不是一个标准的promise对象
if (isPromise(action)) {
// 如果action是一个promise 则将其resolve的值(action)进行dispatch
action.then(dispatch);
} else if (isPromise(action.payload)) {
// 或者action.payload是一个promise 则将其resolve的值(action)进行dispatch
action.payload
.then(function (result) {
dispatch({ ...action, payload: result });
})
.catch(function (error) {
dispatch({ ...action, payload: error, error: true });
return Promise.reject(error);
});
} else {
//否者交给其他中间件来处理
next(action);
}
};
};
}