dispatch multiple actions in one effect
@Effect()loadInitConfig$ = this.actions$ .ofType(layout.ActionTypes.LOAD_INIT_CONFIGURATION) .map<Action, void>(toPayload) .switchMap(() => this.settingsService .loadInitConfiguration() .mergeMap((data: any) => [ new layout.LoadInitConfigurationCompleteAction(data.settings), new meetup.LoadInitGeolocationCompleteAction(data.geolocation) ]) .catch(error => Observable.of( new layout.LoadInitConfigurationFailAction({ error }) ) ) );
You can use switchMap
and Observable.of
.
@Effect({ dispatch: true }) action$ = this.actions$ .ofType(CoreActionTypes.MY_ACTION) .switchMap(() => Observable.of( // subscribers will be notified {type: 'ACTION_ONE'} , // subscribers will be notified (again ...) {type: 'ACTION_TWO'} )) .catch(() => Observable.of({ type: CoreActionTypes.MY_ACTION_FAILED }));
Performance matters :
Instead of dispatching many actions that will trigger all the subscribers as many times as you dispatch, you may want to take a look into redux-batched-actions.
This allows you to warn your subscribers only when all of those multiple actions have been applied to the store.
For example :
@Effect({ dispatch: true }) action$ = this.actions$ .ofType(CoreActionTypes.MY_ACTION) // subscribers will be notified only once, no matter how many actions you have // not between every action .map(() => batchActions([ doThing(), doOther() ])) .catch(() => Observable.of({ type: CoreActionTypes.MY_ACTION_FAILED }));
If anyone wonders how to mix plain actions with ones from Observables.
I was stuck with same task, but small difference: I needed to dispatch two actions, with second one after API call, which made it an Observable. Something like:
action1
is just an action:{type: 'ACTION_ONE'}
action2
is API call mapped to action:Observable<{type: 'ACTION_TWO'}>
Following code solved my issue:
@Effect() action$ = this.actions$.pipe( ofType(CoreActionTypes.MY_ACTION), mergeMap(res => // in order to dispatch actions in provided order concat( of(action1), action2 ) ), catchError(() => Observable.of({ type: CoreActionTypes.MY_ACTION_FAILED })));