web-dev-qa-db-ja.com

コンポーネントからアクションがディスパッチされるときにngrxエフェクトが呼び出されない

私は、ngrxストアがそれを処理するはずの効果に対するアクションをディスパッチしないという問題を抱えています。

ディスパッチを試みるコンポーネントは次のとおりです。

  signin() {
    this.formStatus.submitted = true;
    if (this.formStatus.form.valid) {
      this.store.dispatch(new StandardSigninAction(this.formStatus.form.value.credentials));
    }
  }

アクション:

export const ActionTypes = {
  STANDARD_SIGNIN: type('[Session] Standard Signin'),
  LOAD_PERSONAL_INFO: type('[Session] Load Personal Info'),
  LOAD_USER_ACCOUNT: type('[Session] Load User Account'),
  RELOAD_PERSONAL_INFO: type('[Session] Reload Personal Info'),
  CLEAR_USER_ACCOUNT: type('[Session] Clear User Account')
};

export class StandardSigninAction implements Action {
  type = ActionTypes.STANDARD_SIGNIN;

  constructor(public payload: Credentials) {
  }
}
...

export type Actions
  = StandardSigninAction
  | LoadPersonalInfoAction
  | ClearUserAccountAction
  | ReloadPersonalInfoAction
  | LoadUserAccountAction;

の効果:

  @Effect()
  standardSignin$: Observable<Action> = this.actions$
    .ofType(session.ActionTypes.STANDARD_SIGNIN)
    .map((action: StandardSigninAction) => action.payload)
    .switchMap((credentials: Credentials) =>
      this.sessionSigninService.signin(credentials)
        .map(sessionToken => {
          return new LoadPersonalInfoAction(sessionToken);
        })
    );

デバッグでは、コンポーネントがdispatchメソッドを呼び出すことがわかります。コンストラクターのブレークポイントにヒットしたため、StandardSigninActionが実際にインスタンス化されていることも確認できます。

しかし standardSignin$エフェクトは呼び出されません...

呼び出されない効果を引き起こす可能性があるものは何ですか?

ストア内で行われていることをデバッグするにはどうすればよいですか?

誰か助けてくれますか?

追伸私はインポートで次のように上記の効果を実行します:

EffectsModule.run(SessionEffects),

編集:これは私のSessionSigninService.signinメソッドです(Observableを返します)

  signin(credentials: Credentials) {
    const headers = new Headers({'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'});
    const options = new RequestOptions({headers: headers});
    const body = 'username=' + credentials.username + '&password=' + credentials.password;
    return this.http.post(this.urls.AUTHENTICATION.SIGNIN, body, options).map(res => res.headers.get('x-auth-token'));
  }
14
balteo

これは決定的な答えになるわけではありませんが、うまくいけば、役に立つでしょう。

始める前に:

  • @ngrxパッケージの最新バージョンを使用していることを確認してください(Angularのバージョンに適しています)。
  • パッケージを更新した場合は、必ず開発環境を再起動してください(つまり、バンドラー、サーバーなどを再起動してください)。

まだ行っていない場合は、 Storeの実装 を見てください。そうすれば、何が間違っているのかについて、経験に基づいた推測を行うことができます。 Storeはかなり軽いことに注意してください。オブザーバブル(状態をソースとして使用)とオブザーバー(ディスパッチャーに任せる)の両方です。

store.dispatch を見ると、 store.next のエイリアスであることがわかります。これは nextDispatcherを呼び出します=。

だから呼び出す:

this.store.dispatch(new StandardSigninAction(this.formStatus.form.value.credentials));

ディスパッチャから発行されたアクションが表示されるだけです。

エフェクトに挿入される Actions observableもかなり軽いです。 Dispatcherをソースとして使用する単なるオブザーバブルです。

エフェクトを流れるアクションを見るために、これを置き換えることができます:

@Effect()
standardSignin$: Observable<Action> = this.actions$
  .ofType(session.ActionTypes.STANDARD_SIGNIN)

これとともに:

@Effect()
standardSignin$: Observable<Action> = this.actions$
  .do((action) => console.log(`Received ${action.type}`))
  .filter((action) => action.type === session.ActionTypes.STANDARD_SIGNIN)

ofTypeは演算子ではありません。メソッドであるため、doベースのロギングを追加するには、filterに置き換える必要があります。

ロギングが適切に行われている場合、アクションを受け取っている場合、エフェクトの実装に何らかの問題があります(または、アクションタイプの文字列/定数が、あなたが思っているものではなく、何かが一致していない可能性があります)。

エフェクトがディスパッチされたアクションを受け取っていない場合、最も可能性の高い説明は、storeをディスパッチしているStandardSigninActionが、エフェクトが使用しているstoreと同じではないことです。つまり、DIの問題があります。

その場合は、動作していると言う他のSessionEffectsと異なるものを調べる必要があります。 (少なくとも、何か機能するものがあり、実験を始めるのに適しています。)それらは別のモジュールからディスパッチされていますか? StandardSigninActionをディスパッチするモジュールは機能モジュールですか?

作業中のSessionEffectsの1つをハックして、ディスパッチされたアクションをStandardSigninActionに置き換えた場合はどうなりますか?その後、エフェクトは実行されますか?

この回答の最後にある質問は、私が答えたい質問ではないことに注意してください。それらはあなた自身に尋ね、調査するべき質問です。

16
cartant

ストアのストリームは、未処理のエラーまたは-おそらくもっとわかりにくい-.catchは、物事を続けるために新しいObservableを再送信することなく、実際にストリームを強制終了します。

たとえば、これはストリームを殺します:

this.actions$
    .ofType('FETCH')
    .map(a => a.payload)
    .switchMap(query => this.apiService.fetch$(query)
        .map(result => ({ type: 'SUCCESS', payload: result }))
        .catch(err => console.log(`oops: ${err}`))) // <- breaks stream!

しかし、これは物事を生き続けます:

this.actions$
    .ofType('FETCH')
    .map(a => a.payload)
    .switchMap(query => this.apiService.fetch$(query)
        .map(result => ({ type: 'SUCCESS', payload: result }))
        .catch(e => Observable.of({ type: 'FAIL', payload: e}))) // re-emit

これは、rxjs Observable btwにも当てはまります。これは、複数のオブザーバーにブロードキャストするときに考慮することが特に重要です(ngrxストアが内部Subjectを使用して内部的に行うように)。

7
rob3c

私はngrxの新しいバージョン(7.4.0)を使用しているため、cartanの提案は次のとおりです。

.do((action) => console.log(`Received ${action.type}`))

あるべき...

... = this.actions.pipe(
   tap((action) => console.log(`Received ${action.type}`)),
   ...

そして最後に、次のような新しいエフェクトエクスポートをモジュールに追加するのを忘れていたことがわかりました。

EffectsModule.forRoot([AuthEffects, ViewEffects]),  // was missing the ', ViewEffects'
0
Adam Cox