I'm using redux-observable to handle an action:
export const createPaymentMethod =
(getBraintreeToken: (Object) => Promise<*>, cardholderName: string) => ({
type: CREATE_PAYMENT_METHOD,
getBraintreeToken: () => getBraintreeToken({ cardholderName }),
});
const mapBraintreeError = err => Observable.of({
type: CREATE_PAYMENT_METHOD + FAILURE,
error: { response: err.message },
});
export const createPaymentMethodEpic = (action$: any, store: ReduxState) =>
action$.ofType(CREATE_PAYMENT_METHOD)
.switchMap(({ getBraintreeToken }) => Observable.fromPromise(getBraintreeToken()))
.switchMap(({ nonce }) =>
ajax(api.createPaymentMethod(store.billings.info.customer_id, nonce))
.mapSuccess(CREATE_PAYMENT_METHOD)
.mapFailure(CREATE_PAYMENT_METHOD),
)
.catch(mapBraintreeError);
What I do is I intentionally make getBraintreeToken()
Promise fail. This results in epic execute catch
function and returning CREATE_PAYMENT_METHOD + FAILURE
action. Which is what I intended.
The problem is when I try to call epic the second time. It doesn't execute...
EDIT: I have converted the epic and it seems to work now, however, I still don't understand why the first example was broken (actually I like more the flat structure of the first epic).
export const createPaymentMethodEpic = (action$: any, store: ReduxState) =>
action$.ofType(CREATE_PAYMENT_METHOD)
.switchMap(({ getBraintreeToken }) =>
Observable.fromPromise(getBraintreeToken())
.switchMap(({ nonce }) =>
ajax(api.createPaymentMethod(store.billings.info.customer_id, nonce))
.mapSuccess(CREATE_PAYMENT_METHOD)
.mapFailure(CREATE_PAYMENT_METHOD),
)
.catch(mapBraintreeError),
);
mapTo
ormap
to avoid using error catching as the primary path. Depends on what's insidegetBraintreeToken()
and how the error message is generated. Could you postgetBraintreeToken()
(if still hunting for optimization). – Richard MatsengetBraintreeToken
from external api, so I would probably have to wrap it in some other promise to avoid catch block... – Tomasz Mularczyk