当前项目中很多处理耗时较长,单个API请求我们可以加拦截器做到loading的开启和关闭,但是假如是一个effects中包含了多个请求,同时夹杂了一些其它的逻辑,那么单纯靠API层的loading控制是不行的,并且还会出现抖动开关。so,我们需要做到saga-effects这层的loading控制。
目标效果
当发起一个saga监听的action时,loading遮罩开启,当effects执行结束时,关闭。
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| import { call, put } from 'redux-saga/effects'; import * as is from '@redux-saga/is';
const LOADING_BLACKLIST = [UserActionTypes.GET_USERS];
function isForkEffect(eff) { return is.effect(eff) && eff.type === 'FORK'; }
function loading(sagaFn) { return function* (action) { function* loadingWrapper() { yield put(loadingStatusAction(true)); yield call(sagaFn, action); yield put(loadingStatusAction(false)); }
if (LOADING_BLACKLIST.includes(action.type)) { return yield call(sagaFn, action); } else { return yield call(loadingWrapper, action); } }; }
const effectMiddleware = next => eff => { if (isForkEffect(eff)) { eff.payload.args[1] = safe(eff.payload.args[1]); eff.payload.args[1] = loading(eff.payload.args[1]); } return next(eff); };
export const sagaMiddleware = createSagaMiddleware({ effectMiddlewares: [effectMiddleware], onError: sagaEffectUnhandled });
|
大致说明
- loading是个高阶函数,在sagaFn执行前后,分别加入loading的开启和关闭。
- sagaFn是个生成器函数,这里包装完还是个生成器函数
写在最后
- 假如不利用中间件,就需要在很多地方重复的loading开启和关闭逻辑,违反了DRY原则。so,这么做还是有价值的。