angular - español - ¿Cómo acceder al árbol de estado en los efectos?(@ ngrx/efectos 2.x)
ngrx store angular 6 (2)
Estoy actualizando @ngrx/effects de 1.x a 2.x
En 1.x tengo acceso del árbol de estado en efecto:
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 }));
Ahora en 2.x, solo me da acción. ¿Todavía hay una manera de obtener acceso al árbol de estado? ¿O debería evitar usar así porque no es una buena práctica?
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 }));
Los efectos no tienen que ser propiedades de clase; También pueden ser métodos. Lo que significa que puede acceder a una tienda que está inyectada en el constructor.
Al momento de escribir esta respuesta, la semántica de las declaraciones de propiedad y public
parámetros de constructor public
/ private
no estaban claras para mí. Si las propiedades se declaran después del constructor, pueden acceder a los miembros public
/ private
declarados a través de los parámetros del constructor, por lo que no tiene que declarar sus efectos como funciones.
Con la tienda inyectada, debería poder usar un operador como mergeMap
para obtener el estado y combinarlo con la actualización que recibió:
@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 }));
}
}
Si hacer esto o no es una buena práctica es una cuestión de opinión, supongo. Leer el estado, idealmente al componer un selector de estilo ngrx, suena razonable, pero sería más limpio si toda la información que necesitaba para un efecto en particular se incluyera en la acción que estaba escuchando.
Otra forma es usando .withLatestFrom(this.store)
. Así que el código completo es:
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 }));