Redux Observables を使用して別のアクションをディスパッチする前に、一連のアクションを待機する必要があるユースケースがあります。 同様の質問をいくつか見たことがありますが、特定のユースケースでこれらのアプローチをどのように使用できるかわかりません。
本質的には、次のようなことをしたいのです。
action$
.ofType(PAGINATION_CLICKED) // This action occurred.
.ofType(FETCH_SUCCESS) // Then this action occurred after.
.map(() => analyticsAction()); // Dispatch analytics.
FETCH_ERROR
たとえば、別のタイプのアクションが起動された場合は、そのシーケンスをキャンセルして最初からやり直したいと思います。
ベストアンサー1
素晴らしい質問です。重要な点は、action$
ディスパッチされるすべてのアクションのホット/マルチキャスト ストリームであることです (これはサブジェクトです)。ホットなので、複数回組み合わせることができ、それらはすべて同じアクション ストリームをリッスンします。
// uses switchMap so if another PAGINATION_CLICKED comes in
// before FETCH_SUCCESS we start over
action$
.ofType(PAGINATION_CLICKED)
.switchMap(() =>
action$.ofType(FETCH_SUCCESS)
.take(1) // <-------------------- very important!
.map(() => analyticsAction())
.takeUntil(action$.ofType(FETCH_ERROR))
);
したがって、受信するたびに、PAGINATION_CLICKED
単一の をリッスンする内部 Observable チェーンのリッスンを開始しますFETCH_SUCCESS
。これが重要なのは、.take(1)
そうしないと、複数の をリッスンし続けることになりFETCH_SUCCESS
、奇妙なバグが発生する可能性があるためです。また、そうでなくても、必要なものだけを取得するのが一般的にベストプラクティスです。
先に受信した場合、takeUntil
待機をキャンセルするために使用します。FETCH_SUCCESS
FETCH_ERROR
ボーナスとして、エラーに基づいて分析も行いたい場合は、最初からやり直すだけでなく、 をrace
2 つのストリーム間で実際に競合させるために使用できます。最初に送信したものが勝ち、もう一方はサブスクライブ解除されます。
action$
.ofType(PAGINATION_CLICKED)
.switchMap(() =>
Observable.race(
action$.ofType(FETCH_SUCCESS)
.take(1)
.map(() => analyticsAction()),
action$.ofType(FETCH_ERROR)
.take(1)
.map(() => someOtherAnalyticsAction())
)
);
これは同じものですが、race
静的演算子の代わりにインスタンス演算子として使用しています。これは選択できるスタイル上の好みです。どちらも同じことを行います。よりわかりやすい方を使用してください。
action$
.ofType(PAGINATION_CLICKED)
.switchMap(() =>
action$.ofType(FETCH_SUCCESS)
.map(() => analyticsAction())
.race(
action$.ofType(FETCH_ERROR)
.map(() => someOtherAnalyticsAction())
)
.take(1)
);