Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a generic redux-saga factory automatically handling async-actions - createAsyncSaga #218

Open
edgarSang opened this issue Dec 16, 2019 · 2 comments

Comments

@edgarSang
Copy link

edgarSang commented Dec 16, 2019

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??

@piotrwitek
Copy link
Owner

piotrwitek commented Dec 24, 2019

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.

@piotrwitek piotrwitek changed the title How to use AsyncActionCreatorBuilder Add a generic redux-saga factory automatically handling async-actions - createAsyncSaga Dec 24, 2019
@ifmoon
Copy link

ifmoon commented Jan 23, 2020

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants