web-dev-qa-db-ja.com

ngrxはエラー処理に影響します

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

、しかし、これは無限ループになります...後でエフェクトの実行を妨げることなくエラーをキャッチする方法を知っていますか?

22
highwaychile

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は、エフェクトにフラット化またはマージされた空のオブザーバブルが表示されるため、アクションは発生しません。

20
cartant

@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ストリームを継続

4
iamturns

これは、データを見つけられなかった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())));
    }
1
born2net