como throwError no switchMap no efeito ngrx
Estou usando ngrx8, rxjs6 e angular 9
Após o login, preciso ligar para outro serviço. quando esse serviço está lançando um erro, eu quero catchError parte do meu efeito para lidar com isso, o problema é que eu pego o erro em try catch e vejo o log, mas catchError
não é acionado.
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 }));
}),
);
});
meu código real
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 }));
}),
);
});
saída do console

Respostas
Em vez de usar Async-Await
a sintaxe para aguardar a conclusão do Promise
retornado por matrixService.initClient
(o que não funcionaria no contexto atual devido ao switchMap
operador não aguardar async
as funções), considere retorná-lo sem esperar, pois seria convertido em um Observable
(graças ao switchMap
operador aceitando Promise
) resultando em this.userService.login
sendo aguardado.
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 }));
})
)
);
com base nos comentários, modificarei um pouco as respostas 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 }));
})
)
);
Eu mudo a ordem, sempre atirando AuthActions.loginSuccess()
e depois this.matrixService.initClient(userName, password)
.
catchError
não precisa ser chamado duas vezes, qualquer erro gerado na chamada de serviço será capturado no catchError
operador mais externo.