@ngrxエフェクトに関する非常に基本的な質問があります:エフェクトの実行中に発生するエラーを無視して、将来のエフェクトの実行に影響を与えないようにするにはどうすればよいですか?
私の状況は次のとおりです。アクション(ログイン)と、そのアクションをリッスンするエフェクトがあります。このエフェクト内でエラーが発生した場合、無視します。このエラーの後にLOGINが2回送信されると、エフェクトが2回実行されます。
これを行う最初の試みは次のとおりです。
@Effect()
login$ = this.actions$
.ofType('LOGIN')
.flatMap(async () => {
console.debug('LOGIN');
// throw an error
let x = [];x[0]();
})
.catch(err => {
console.error('Error at login', err);
return Observable.empty();
});
初めてLOGINをディスパッチすると、期待どおりにエラーがスローおよびキャッチされます。ただし、その後LOGINを再度ディスパッチしても、何も起こりません。効果は実行されません。
したがって、私は次を試しました:
.catch(err => {
return this.login$;
});
、しかし、これは無限ループになります...後でエフェクトの実行を妨げることなくエラーをキャッチする方法を知っていますか?
ngrx
インフラストラクチャは、EffectsModule.run
を使用してアプリのNgModule
にインポートされたプロバイダーを介してエフェクトにサブスクライブします。
監視可能エラーとcatch
が空の監視可能を返す場合、構成された監視可能オブジェクトは完了し、そのサブスクライバーはサブスクライブされません-それは Observable Contract 。そして、それがあなたがあなたのエフェクトでLOGIN
アクションのさらなる処理を見ない理由です。効果は完了時にサブスクライブされず、ngrx
インフラストラクチャは再サブスクライブしません。
通常、flatMap
(現在はmergeMap
と呼ばれる)内でエラー処理が行われます。
import { Actions, Effect, toPayload } from "@ngrx/effects";
@Effect()
login$ = this.actions$
.ofType('LOGIN')
.map(toPayload)
.flatMap(payload => Observable
.from(Promise.reject('Boom!'))
.catch(error => {
console.error('Error at login', error);
return Observable.empty();
})
});
内側のオブザーバブルに組み込まれたcatch
は、エフェクトにフラット化またはマージされた空のオブザーバブルが表示されるため、アクションは発生しません。
@Effect
ストリームは、エラーが発生するとcompletingになり、それ以上のアクションを防ぎます。
解決策は、使い捨てストリームに切り替えることです。使い捨てストリーム内でエラーが発生した場合、メイン@Effect
ストリームは常に有効であり、今後のアクションは引き続き実行されます。
@Effect()
login$ = this.actions$
.ofType('LOGIN')
.switchMap(action => {
// This is the disposable stream!
// Errors can safely occur in here without killing the original stream
return Rx.Observable.of(action)
.map(action => {
// Code here that throws an error
})
.catch(error => {
// You could also return an 'Error' action here instead
return Observable.empty();
});
});
このブログ投稿でこの手法の詳細をご覧ください: ミートボールのクエスト:エラー発生時にRxJSストリームを継続
これは、データを見つけられなかったObservablesで通知されるか通知されないかのオプションを処理する方法です。
public listenCampaignValueChanged(emitOnEmpty: boolean = false): Observable<CampaignsModelExt> {
var campaignIdSelected$ = this.ngrxStore.select(store => store.appDb.uiState.campaign.campaignSelected)
var campaigns$ = this.ngrxStore.select(store => store.msDatabase.sdk.table_campaigns);
return campaignIdSelected$
.combineLatest(campaigns$, (campaignId: number, campaigns: List<CampaignsModelExt>) => {
return campaigns.find((i_campaign: CampaignsModelExt) => {
return i_campaign.getCampaignId() == campaignId;
});
}).flatMap(v => (v ? Observable.of(v) : ( emitOnEmpty ? Observable.of(v) : Observable.empty())));
}