Website-Suche

angular - Wie erhält man Zugriff auf den Zustandsbaum in Effekten? (@ngrx/effects 2.x)


Ich aktualisiere @ngrx/effects von 1.x auf 2.x

In 1.x habe ich Zugriff auf den Zustandsbaum in den Effekten:

  constructor(private updates$: StateUpdates<AppState>) {}

  @Effect() bar$ = this.updates$
    .whenAction(Actions.FOO)
    .map(obj => obj.state.user.isCool)
    .distinctUntilChanged()
    .filter(x => x)
    .map(() => ({ type: Actions.BAR }));

Jetzt in 2.x gibt es mir nur Aktion. Gibt es immer noch eine Möglichkeit, auf den State-Baum zuzugreifen? Oder sollte ich es vermeiden, es so zu verwenden, weil es keine gute Praxis ist?

  constructor(private actions$: Actions) {}

  @Effect() bar$ = this.actions$
    .ofType(ActionTypes.FOO)
    .map((obj: any) => {
      console.log(obj);              // here is action only
      return obj.state.user.isCool   // so it is wrong here
    })
    .distinctUntilChanged()
    .filter(x => x)
    .map(() => ({ type: ActionTypes.BAR }));

Antwort #1

Eine andere Möglichkeit ist die Verwendung von .withLatestFrom(this.store). Der komplette Code ist also:

  constructor(
    private actions$: Actions,
    private store: Store<AppState>
  ) {}

 @Effect() bar$ = this.actions$
    .ofType(ActionTypes.FOO)
    .withLatestFrom(this.store, (action, state) => state.user.isCool)
    .distinctUntilChanged()
    .filter(x => x)
    .map(() => ({ type: ActionTypes.BAR }));

Antwort #2

Effekte müssen keine Klassen-Eigenschaften sein; sie können auch Methoden sein. Das bedeutet, dass Sie auf einen Store zugreifen können, der in den Konstruktor eingefügt wurde.

Zum Zeitpunkt des Schreibens dieser Antwort waren mir die Semantik von Eigenschaftserklärungen und public/private Konstruktorparametern nicht klar. Wenn Eigenschaften nach dem Konstruktor deklariert werden, können sie auf die public/private Mitglieder zugreifen, die über Konstruktorparameter deklariert wurden - somit muss man seine Effekte nicht als Funktionen deklarieren.

Mit dem injizierten Store sollten Sie in der Lage sein, einen Operator wie mergeMap zu verwenden, um den Zustand zu erhalten und ihn mit dem erhaltenen Update zu kombinieren:

@Effect()
bar$(): Observable<Action> {

  return this.actions$
    .ofType(ActionTypes.FOO)
    .mergeMap((update) => this.store.first().map((state) => ({ state, update })))
    .map((both) => {
      // Do whatever it is you need to do with both.update and both.state.
      return both.update;
    })
    .distinctUntilChanged()
    .filter(x => x)
    .map(() => ({ type: ActionTypes.BAR }));
  }
}

Ob dies gute Praxis ist oder nicht, ist meiner Meinung nach Ansichtssache. Den Zustand zu lesen - idealerweise durch das Zusammensetzen eines ngrx-ähnlichen Selectors - klingt sinnvoll, aber es wäre sauberer, wenn alle Informationen, die Sie für einen bestimmten Effekt benötigen, in der Aktion enthalten wären, auf die er lauscht.

Verwandte Artikel