Add a generic redux-saga factory automatically handling async-actions - createAsyncSaga
edgarSang opened this issue · comments
I used typescript typesafe-actions v4
and I created Saga common function
like this
export default function createAsyncSaga<T1, P1, T2, P2, T3, P3>(
asyncActionCreator: AsyncActionCreator<[T1, P1], [T2, P2], [T3, P3]>,
promiseCreator: PromiseCreatorFunction<P1, P2>,
) {
return function* saga(action: ReturnType<typeof asyncActionCreator.request>) {
try {
const result = isPayloadAction<P1>(action)
? yield call(promiseCreator, action.payload)
: yield call(promiseCreator);
yield put(asyncActionCreator.success(result));
} catch (e) {
yield put(asyncActionCreator.failure(e));
}
};
}
With this common function, I was able to create a single line of sagas.
like this
const getUserProfileSaga = createAsyncSaga(getUserProfileAsync, getUserProfile);
but in v5 i can't use this source code.
becuase of AsyncActionCreatorBuilder
(error message is Type '[T1, P1]' does not satisfy the constraint '[T1, [T1, P1] ....ommited..)
How do I change my source code??
Hey @edgarSang,
I will try to help you but I need all the missing details like:
- what is PromiseCreatorFunction<P1, P2> type
- what is isPayloadAction
I might even consider adding it to the library as a build-in helper function.
I'll be waiting for your response.
hi, here is v5 createAsyncSaga. it worked.
interface AsyncActionGroup<
T1 extends string,
P1,
T2 extends string,
P2,
T3 extends string,
P3
> {
request: EmptyActionCreator<T1> | PayloadActionCreator<T1, P1>;
success: EmptyActionCreator<T2> | PayloadActionCreator<T2, P2>;
failure: EmptyActionCreator<T3> | PayloadActionCreator<T3, P3>;
}
type PromiseCreatorFunction<P, T> =
| ((payload: P) => Promise<T>)
| (() => Promise<T>);
function isPayloadAction<P>(action: any): action is PayloadAction<string, P> {
return action.payload !== undefined;
}
export default function createAsyncSaga<
T1 extends string,
P1,
T2 extends string,
P2,
T3 extends string,
P3
>(
asyncActionGroup: AsyncActionGroup<T1, P1, T2, P2, T3, P3>,
promiseCreator: PromiseCreatorFunction<P1, P2>,
) {
return function* saga(action: ReturnType<typeof asyncActionGroup.request>) {
try {
const result = isPayloadAction<P1>(action)
? yield call(promiseCreator, action.payload)
: yield call(promiseCreator);
yield put(asyncActionGroup.success(result));
} catch (e) {
yield put(asyncActionGroup.failure(e));
}
};
}
I think this function is useful for reducing boilerplate, but I don't think it's suitable as a built-in helper. This is because there is more work to modify the boilerplate itself, such as state management of asynchronous requests, logging, and selector mapping.