I want to model the following async logic using redux:
I am not sure where to put this logic. Actions don't know about other actions, they only have access to dispatch, so they can't stop and wait for them to complete. Reducers don't have access to dispatch, so I can't put it there… so where does it live? Custom middleware? store.listen? In a smart component?
I'm currently using redux-promise-middleware & redux-thunk. How would one best organise this type of flow – without requiring buy-in into something like redux-saga or redux-rx, etc?
Also not sure best way to transparently interrupt the API call to perform those other actions i.e. API call shouldn't trigger its completed or failed actions until after the optional login process completes.
It sounds to me like you'd want an action creator that generates a Thunk, and keep all that logic in the Thunk. There's really no other good way to preserve the association between your suite of API calls, and ensure that all the others are cancelled if one fails.
In that Thunk, you'd fire your API calls, and collect their promises:
const call1 = promiseGenerator1();
const call2 = promiseGenerator2();
const call3 = promiseGenerator3();
const allCallPromises = [call1, call2, call3];
Use an all()
promise handler to monitor them:
const watcher = Promise.all(allCallPromises).then(allSuccess, anyFail);
Your fail handler will:
dispatch an action or route-change to trigger the re-login window
anyFail(error) => {
if (error.status === 401) {
allCallPromises.forEach((item)=> {item.cancel();});
reLogin();
}
}
Then, I'd be inclined to let your relogin component worry about re-firing that same complex action again, to issue all the calls.
However, should your suite of API calls be somehow variable or context-specific, you could cache on the store the ones you need, from inside the anyFail
handler. Have a reducer where you can stash an actionPendingReLogin
. Compose an action that will re-fire the same calls as last time, and then dispatch it:
dispatch(createAction('CACHE_RELOGIN_ACTION`, actionObjectToSaveForLater));
(Or, just cache whatever action-creator you used.)
Then, following successful relogin, you can:
const action = store.getState('actionPendingReLogin');
dispatch(action);
// or:
const actionCreator = store.getState('actionPendingReLogin');
dispatch(actionCreator());
Oh: and in your allSuccess
handler you'd simply dispatch the results of the async calls.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With