最近在读Redux相关源码,现将自己实现的代码和理解贴上,后期再补充详细~
使用redux-promise中间件,允许action是一个promise,在promise中,如果要触发action,则通过调用resolve来触发。
实现原理:如果action是一个promise,则会等待promise完成,将完成的结果作为action触发,如果action不是一个promise,则判断其payload是否是一个promise,如果是,等待promise完成,然后将得到的结果作为payload的值触发。
实现redux-promise:先判断action是不是一个标准的flux action(这里使用了一个第三方库is-promise,判断参数是否是promsie)
import { isPlainObject, isString } from "lodash"
import isPromise from "is-promise"
export default ({ dispatch }) => next => action => {
if (!isFSA(action)) {
//如果不是一个标准的action
//如果action是一个promise,则将其resolve的值dispatch,否则,不做任何处理,交给下一个中间件
return isPromise(action) ? action.then(dispatch) : next(action);
}
return isPromise(action.payload) ?
action.payload
.then(payload => dispatch({ ...action, payload }))
.catch(error => dispatch({ ...action, payload: error, error: true })) :
next(action)
}
/**
* 判断一个action是不是标准的flux的action
* @param {*} action
*/
function isFSA(action) {
//action必须是一个平面对象 plain-object
//action.type必须是一个字符串
//action的属性不能包含其他非标准属性 标准属性["type", "payload", "error", "meta"]
return isPlainObject(action)
&&
isString(action.type)
&&
Object.keys(action).every(key => ["type", "payload", "error", "meta"].includes(key));
}
redux-promise的几种使用方法,以下都是在action生成器中的使用场景:
// 直接返回一个promise
export function fetchStudents() {
return new Promise(resolve => {
setTimeout(() => {
const action = setStudentAndTotal([{ id: 1, name: 'zc' }, { id: 2, name: 'gg' }],100)
resolve(action);
},1000)
})
}
// 结合async await使用
export async function fetchStudents(condition) {
const resp = await searchStudents(condition)
return setStudentAndTotal(resp.datas, resp.cont);
}
// payload接收一个promise
export async function fetchStudents(condition) {
return {
type: actionTypes.setStudentAndTotal,
payload: await searchStudents(condition).then(resp => ({
datas: resp.datas,
total: resp.cont
}))
}
}