Отправлять несколько действий одним действием

Я хотел бы выделить два действия одним эффектом. В настоящее время я должен объявить два эффекта для достижения этого:

  // first effect
  @Effect() action1$ = this.actions$
    .ofType(CoreActionTypes.MY_ACTION)
    .map(res => {
      return { type: "ACTION_ONE"}
    })
    .catch(() => Observable.of({
      type: CoreActionTypes.MY_ACTION_FAILED
    }));

  // second effect
  @Effect() action2$ = this.actions$
    .ofType(CoreActionTypes.MY_ACTION)
    .map(res => {
      return { type: "ACTION_TWO"}
    })
    .catch(() => Observable.of({
      type: CoreActionTypes.MY_ACTION_FAILED
    }));

Возможно ли иметь одно действие, быть источником двух действий с помощью одного эффекта?

Ответ 1

@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
                    })
                )
            )
    );

Ответ 2

Вы можете использовать switchMap и 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
    }));

Эффективность:

Вместо того, чтобы отправлять много действий, которые будут запускать все подписчики столько раз, сколько вы отправляете, вы можете взглянуть на redux-batched-actions.

Это позволяет вам предупреждать своих подписчиков только в том случае, если все эти несколько действий были применены к хранилищу.

Например:

@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
    }));

Ответ 3

Вы можете выбрать mergeMap для async или concatMap для синхронизации

  @Effect() action$ = this.actions$
    .ofType(CoreActionTypes.MY_ACTION)
    .mergeMap(() => Observable.from([{type: "ACTION_ONE"} , {type: "ACTION_TWO"}]))
    .catch(() => Observable.of({
      type: CoreActionTypes.MY_ACTION_FAILED
    }));

Ответ 4

вы также можете использовать .do() и store.next()

do позволяет присоединить обратный вызов наблюдаемому, не затрагивая других операторов/изменяя наблюдаемый

например.

@Effect() action1$ = this.actions$
.ofType(CoreActionTypes.MY_ACTION)
.do(myaction => this.store.next( {type: 'ACTION_ONE'} ))
.switchMap((myaction) => Observable.of(
    {type: 'ACTION_TWO'}
))
.catch(() => Observable.of({
  type: CoreActionTypes.MY_ACTION_FAILED
}));

(вам понадобится ссылка на хранилище в вашем классе эффектов)

Ответ 5

Если кому-то интересно, как смешать простые действия с действиями из Observables.

Я застрял с той же задачей, но с небольшой разницей: мне нужно было отправить два действия, второе после вызова API, что сделало его наблюдаемым. Что-то вроде:

  1. action1 - это просто действие: {type: 'ACTION_ONE'}
  2. action2 - это вызов API, сопоставленный с action: Observable<{type: 'ACTION_TWO'}>

Следующий код решил мою проблему:

@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
    }))
);

Concat Doc's