web-dev-qa-db-ja.com

1つの効果で複数のアクションをディスパッチします

1つの効果で2つのアクションをダイパッチします。現在、これを達成するには2つの効果を宣言する必要があります。

  // 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つのアクションを持ち、1つのエフェクトを介して2つのアクションのソースになることは可能ですか?

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

switchMapObservable.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
    }));
10
maxime1992

単純なアクションとObservablesのアクションを混在させる方法を誰もが疑問に思っている場合。

私は同じタスクで立ち往生しましたが、わずかな違いがありました。2つのアクションをディスパッチする必要があり、2番目のアクションはAPI呼び出しの後で、Observableになりました。何かのようなもの:

  1. action1は単なるアクションです:{type: 'ACTION_ONE'}
  2. action2は、アクションにマップされるAPI呼び出しです: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
    }))
);

連結ドキュメント

4

非同期の場合はmergeMapを、同期の場合は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
Victor Godoy

.do()およびstore.next()を使用することもできます

他の演算子に影響を与えずにオブザーバブルにコールバックを添付できるようにします/オブザーバブルを変更します

例えば.

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

(エフェクトクラスでストアへの参照が必要になります)

2
JusMalcolm