installing - ngrx wikipedia
Cómo realizar múltiples operaciones/efectos/acciones relacionadas con ngrx/effects (4)
Estoy trabajando en una aplicación que está usando ngrx / store 1.5 junto con middleware thunk y estoy intentando moverme a ngrx / store 2.0 y ngrx / effects. Tengo un par de preguntas con respecto a cómo manejar múltiples acciones y / o efectos relacionados.
Me doy cuenta de que la "mentalidad" para los efectos contra los thunks es diferente y estoy tratando de entender las diferencias. He revisado las aplicaciones de ejemplo disponibles y no he encontrado nada que parezca lo que estoy intentando, así que tal vez todavía me estoy equivocando.
escenario 1
Aquí hay un efecto secundario para manejar la solicitud al servidor para iniciar sesión:
@Effect login$: any = this.updates$
.whenAction(LoginActions.LOGIN)
.map(toPayload)
.switchMap(payload =>
this.loginService.login(payload.user, payload.password)
.map(result => this.actions.loginSuccess(value))
.catch((error) => Observable.of(this.loginError(error)))
));
Dado ese efecto colateral inicial, ¿cuál sería la forma "correcta" o "sugerida" de activar la navegación a una pantalla de "inicio" al iniciar sesión correctamente? Esto también podría generalizarse para simplemente activar una secuencia de acciones u operaciones.
Algunas opciones que he considerado:
(a) ¿Otro efecto desencadenado por el éxito de inicio de sesión, que desencadena una acción posterior para activar la navegación?
@Effect navigateHome$: any = this.updates$
.whenAction(LoginActions.LOGIN_SUCCEEDED)
.mapTo(this.actions.navigateHome());
(b) ¿Otro efecto desencadenado por el éxito de inicio de sesión, que simplemente realiza la operación de navegación?
@Effect navigateHome$: any = this.updates$
.whenAction(LoginActions.LOGIN_SUCCEEDED)
.do(this.navigateHome())
.filter(() => false);
(c) Concatenar una acción adicional a las emitidas por el efecto de inicio de sesión inicial? (muestra obviamente no es del todo correcto, pero da la idea)
@Effect login$: any = this.updates$
.whenAction(LoginActions.LOGIN)
.map(toPayload)
.switchMap(password => Observable.concat(
this.loginService.login(passcode)
.map(result => this.actions.loginSuccess(value))
.catch((error) => Observable.of(this.loginError(error))),
Observable.of(this.actions.navigateHome())
));
(d) ¿Otro?
Escenario 2
Considere un caso en el que se deban realizar varias solicitudes en secuencia y, a medida que cada solicitud comience, queremos actualizar el "estado" para que se puedan proporcionar comentarios al usuario.
Ejemplo de un thunk para algo parecido a eso:
multiphaseAction() {
return (dispatch) => {
dispatch(this.actions.updateStatus(''Executing phase 1'');
this.request1()
.flatMap(result => {
dispatch(this.actions.updateStatus(''Executing phase 2'');
return this.request2();
})
.flatMap(result => {
dispatch(this.actions.updateStatus(''Executing phase 3'');
return this.request3();
})
...
}
}
Nuevamente, ¿cuál sería la forma "correcta" o "sugerida" de abordar esto al usar el enfoque de los efectos?
Éste en el que estoy más atascado, no estoy seguro de qué podría hacerse aparte de agregar algo de .do(this.store.dispatch(this.actions.updateStatus(...))
alguna manera ...
Estoy aprendiendo esto también.
¿Qué pasa si te envían al reductor cuando el primero en la cadena estaba hecho?
Algo como esto:
const myReducer = (state,action:Action) => {
switch action.type {
case : "my_first_step" : runfirststep(action.payload);
case : "my_second_step": runsecondstep(action.payload);
....
function runfirststep(data) {
...
//bunch of stuff to do,
//update something to display
store.dispatch(''my_second_step'');
}
etc.
El ejemplo ngrx hace esto en el archivo de efectos. Cuando se agrega o actualiza, ellos llaman a UPDATE_COMPLETE o algo similar, presumiblemente para que se pueda hacer alguna notificación.
Poco a poco me doy cuenta de lo grandes que serán los reductores en una aplicación moderadamente compleja.
La respuesta para el escenario de navegación es tu respuesta b
@Effect navigateHome$: any = this.updates$
.whenAction(LoginActions.LOGIN_SUCCEEDED)
.do(this.router.navigate(''/home''))
.ignoreElements();
Explicación: Usted reacciona a LOGIN_SUCCESS, y como el enrutador no devuelve una nueva acción, debemos detener la propagación de la transmisión, lo cual hacemos filtrando todo.
Si olvida filtrar, el enrutador devuelve indefinido, lo que a su vez conducirá al reductor a reducir un valor indefinido, que generalmente da como resultado un puntero nulo cuando intenta leer el type
de acción.
Otra forma de resolverlo es usar https://github.com/ngrx/router-store
Consulte la documentación sobre cómo agregar el router-store a su aplicación.
El mismo efecto ahora se verá así.
import { go } from ''@ngrx/router-store'';
@Effect navigateHome$: any = this.updates$
.whenAction(LoginActions.LOGIN_SUCCEEDED)
.map(() => go([''/home'']));
La acción go
enviará una acción del enrutador que el enrutador reducirá y activará un cambio de ruta.
escenario 1
Considere si navigateHome
debería cambiar el estado o no. Además, independientemente de si esta acción navigateHome
se envía desde otros lugares para lograr lo mismo. Si es así, devolver una acción es el camino a seguir. Por lo tanto, la opción A.
En algunos casos, la opción B podría tener más sentido. Si navigateHome
solo cambia la ruta, podría valer la pena considerarla.
Nota al ignoreElements : puede usar ignoreElements aquí en lugar del filter(() => false)
.
Escenario 2
Sugeriría encadenar sus acciones aquí en múltiples efectos y dar retroalimentación al modificar el estado en el reductor para cada acción.
Por ejemplo:
@Effect() trigger$: Observable<Action> = this.updates$
.whenAction(Actions.TRIGGER)
.do(() => console.log("start doing something here"))
.mapTo(Actions.PHASE1);
@Effect() phase1$: Observable<Action> = this.updates$
.whenAction(Actions.PHASE1)
.do(() => console.log("phase 1"))
.mapTo(Actions.PHASE2);
@Effect() phase2$: Observable<Action> = this.updates$
.whenAction(Actions.PHASE2)
.do(() => console.log("phase 2"))
.ignoreElements();
Y dar su opinión al modificar el estado:
function reducer(state = initialState, action: Action): SomeState {
switch (action.type) {
case Actions.TRIGGER: {
return Object.assign({}, state, {
triggered: true
});
}
case Actions.PHASE1: {
return Object.assign({}, state, {
phase1: true
});
}
case Actions.PHASE2: {
return Object.assign({}, state, {
phase1: false,
phase2: true
});
}
// ...
}
}
escenario 1
Opción A y B son buenas para ir, creo, pero tal vez la opción A es demasiado para la navegación. También puede usar directamente el enrutador en LoginActions.LOGIN
si considera la navegación como parte de este efecto secundario.
Escenario 2
No hay nada de malo en encadenar @Effects
. Envíe una acción (SET_1_REQUEST) que active su efecto A. el efecto A devuelve una acción (SET_1_SUCCESS) que su reductor recoge (ahora puede mostrar ese estado al usuario) y se capta con el efecto B.
Espero que esto tenga sentido.