In my scenario, when the app loads I dispatch an action that starts an epic to create an API instance, which is necessary to make other API calls:
const connectApiEpic: Epic = (action$, state$) =>
action$.pipe(
ofType('CONNECT_API'),
mergeMap(async (action) => {
const sdk = await AppApi.connect({ url: apiUrl });
return { type: 'SET_API', payload: api };
})
);
The UI is already loaded and the API connection happens in the background. Now if the user clicks a certain search button, I have to dispatch another action (epic) to perform a search, which requires the API to be already connected.
Basically, I need to do something like:
const searchItem: Epic = (action$, rootState$) =>
action$.pipe(
ofType('SEARCH_ITEM'),
mergeMap(async (action) => {
const { api } = rootState$.value;
const item = await api.search(action.item);
return { type: 'SET_ITEM', payload: item };
})
);
However, this will not work until the API is set in the store from connectApiEpic
.
Using redux-observables and rxjs, how could it be made possible to:
So, if api
is what you need to wait for in searchItem
epic, I think this would be an approach:
const searchItem: Epic = (action$, rootState$) =>
action$.pipe(
ofType('SEARCH_ITEM'),
mergeMap(
// waiting for the api to connect first
// if it's already there, everything will happen immediately
action => rootState$.pipe(
map(state => state.api)
filter(api => !!api),
),
),
mergeMap(
api => from(api.search(action.item)).pipe(
map(item => ({ type: 'SET_ITEM', payload: item }))
)
)
);