cómo throwError en switchMap en el efecto ngrx
estoy usando ngrx8, rxjs6 y angular 9
Después de iniciar sesión necesito llamar a otro servicio. cuando ese servicio arroja un error, quiero catchError como parte de mi efecto para manejarlo, el problema es que capturo el error en try catch y veo el registro, pero catchError
no se activa.
Código simplificado
login$ = createEffect(() => {
return this.actions$.pipe(
ofType(AuthActions.login),
switchMap((action) =>
this.userService.login(action.userName, action.password)
.pipe(
switchMap((token) => {
return throwError(new Error('hello'));
}),
map((token) => AuthActions.loginSuccess()),
catchError((error) => {
console.error('error', error); // I don't see this in console
return of(AppError({ error }));
})),
),
catchError((error) => {
console.error('error 2', error);
return of(AppError({ error }));
}),
);
});
mi verdadero codigo
login$ = createEffect(() => {
return this.actions$.pipe(
ofType(AuthActions.login),
switchMap((action) =>
this.userService.login(action.userName, action.password)
.pipe(
switchMap(async (token) => {
try {
await this.matrixService.initClient(action.userName, action.password);
return of(token);
}
catch (error) {
console.log('catch error', error); // I see this in console
return throwError(error);
}
}),
map((token) => AuthActions.loginSuccess()),
catchError((error) => {
console.error('error', error); // I don't see this in console
return of(AppError({ error }));
})),
),
catchError((error) => {
console.error('error 2', error);
return of(AppError({ error }));
}),
);
});
salida de la consola

Respuestas
En lugar de usar Async-Await
la sintaxis para esperar a que se complete el Promise
devuelto por matrixService.initClient
(lo que no funcionaría en el contexto actual debido a que el switchMap
operador no espera async
funciones), considere devolverlo sin esperarlo, ya que se convertiría en un Observable
(gracias al switchMap
operador aceptar Promise
) resultando en this.userService.login
ser esperado.
login$ = createEffect(() => this.actions$
.pipe(
ofType(AuthActions.login),
switchMap(({ userName, password }) => this.userService.login(userName, password)
.pipe(
switchMap(() => this.matrixService.initClient(userName, password)),
map((token) => AuthActions.loginSuccess()),
catchError((error) => {
console.error('error', error);
return of(AppError({ error }));
})
)
),
catchError((error) => {
console.error('error 2', error);
return of(AppError({ error }));
})
)
);
basado en los comentarios, modificaré un poco las respuestas anteriores
login$ = createEffect(() => this.actions$
.pipe(
ofType(AuthActions.login),
switchMap(({ userName, password }) => this.userService.login(userName, password)
.pipe(
map((token) => AuthActions.loginSuccess())
tap(() => this.matrixService.initClient(userName, password)),
)
),
catchError((error) => {
console.error('error 2', error);
return of(AppError({ error }));
})
)
);
Cambio el orden, siempre disparando AuthActions.loginSuccess()
y luego this.matrixService.initClient(userName, password)
.
catchError
no es necesario llamarlo dos veces, cualquier error generado por la llamada de servicio se detectará en el catchError
operador más externo.