How to dispatch multiple actions in ngrx/effect (redux-observable)?

mr__brainwash picture mr__brainwash · May 31, 2018 · Viewed 12.6k times · Source

I am using Angular 6, ngrx/store. I have such effect that is responsible for updating things. Depends on some logic I want to dispatch different actions. What is the difference if I use switchMap insted of map?

This is what I tried but it doesn't work:

 @Effect()
  dispathMultipleActions$ = this.actions$.pipe(
    ofType(ActionTypes.UpdateSomething),
    map(() => {
      const actions: Action[] = [];
      const array = [1, 2, 3, 4, 5];
      array.forEach(item => {
        if (item > 3) {
          actions.push(new DeleteAction(item));
        } else {
          actions.push(new ChangeAction(item));
        }
      });
      return actions;
    })
  );

Answer

Kim Kern picture Kim Kern · May 31, 2018

An effect transforms a stream of actions, so you have a stream of actions as input and output. In your example, you map an action to an array of actions. A stream of arrays of actions is not a valid output type. You need to flatten that array, meaning that you do not emit the array itself into the output stream but instead each of its elements.

Instead of:

input:  --a-------a------>
output: --[b,c]---[b,c]-->

You should do:

input:  --a-------a------>
output: --b-c-----b-c-->

For flattening an Observable of array into Observables of each element, you can use one of the operators mergeMap, switchMap, exhaustMap. In most cases, mergeMap will be the right choice. If you want to learn more about these operators, have a look at this answer.

@Effect()
register$: Observable<Action> = this.actions$.pipe(
  ofType(AuthActionTypes.REGISTER_REQUEST),
  mergeMap((action: RegisterRequest) => {
    // check for register request success
    return [
      new RegisterSuccess(),
      new LoginRequest(action.payload)
    ]
  })
);