Reputation: 616
I'm new to RxJS so sorry if it doesn't make much sense.
Let's say I want to have a reusable epic for fetching a user that will be invoked by action from an app load epic.
Oversimplified example:
const getUserEpic = action$ =>
action$.pipe(
ofType(GET_USER_REQUEST),
switchMap(action => from(service.fetchUser(action.userId).pipe(
mapTo({ type: GET_USER_SUCCESS })))
),
);
const appLoadEpic = action$ =>
action$.pipe(
ofType(LOAD_APP_REQUEST),
map(() => of({ type: GET_USER_REQUEST }, { type: SOME_OTHER_REQUEST }))
);
What if I wanted to call LOAD_APP_SUCCESS
after all of the invoked epics (getUser etc.) finish? It'd be great if it could be done in the appLoadEpic but I'm afraid it's not possible.
Upvotes: 0
Views: 464
Reputation: 18663
The way I would suggest doing it is combining the the individual epics into a "meta"-epic. That is, you can use the individual streams to listen to their individual events and the propagate them when all the merged streams are completed.
const getUserEpic = action$ => ...
const someOtherEpic = action$ => ...
// Creates an epic that merges all the results from each provided epic
const initializationEpic = combineEpics(getUserEpic, someOtherEpic)
const appLoadEpic = (action$, state$) => {
// Runs the new epic with the action and state values.
const onLoad$ = initializationEpic(action$, state$).pipe(
endWith({type: LOAD_APP_SUCCESS})
)
// Listen for the load app request before subscribing to the initialization
action$.pipe(
ofType(LOAD_APP_REQUEST),
mergeMapTo(onLoad$),
)
}
If you are feeling fancy and don't want to have to inject the epics via import, you can also dynamically inject epics The docs detail a way to inject the epic asynchronously, meaning that instead of file injection you could include it as part of the action body during start up, this might make testing a bit easier.
const appLoadEpic = (action$, state$) => {
// Listen for the load app request before subscribing to the initialization
action$.pipe(
ofType(LOAD_APP_REQUEST),
// Now the epic is injected during the app loading, and you run it inline
// here. This makes it easy to mock it during testing
mergeMap(({epic}) => epic(action$, state$).pipe(endWith({type: LOAD_APP_SUCCESS}))),
)
}
Upvotes: 2