comment throwError dans switchMap dans l'effet ngrx
J'utilise ngrx8, rxjs6 et angular 9
Après la connexion, je dois appeler un autre service. lorsque ce service génère une erreur, je veux catchError une partie de mon effet pour le gérer, le problème est que j'attrape l'erreur dans try catch et que je vois le journal, mais qu'il catchErrorn'est pas déclenché.
Code simplifié
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 }));
}),
);
});
Mon vrai code
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 }));
}),
);
});
sortie console
Réponses
Plutôt que d'utiliser Async-Awaitla syntaxe pour attendre que le Promiseretourné par matrixService.initClientse termine (ce qui ne fonctionnerait pas dans le contexte actuel car l' switchMapopérateur n'attend pas les asyncfonctions), envisagez de le renvoyer sans l'attendre, car il serait converti en un Observable(grâce à l' switchMapopérateur accepter Promise) ayant pour résultat d' this.userService.loginêtre attendu.
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 }));
})
)
);
sur la base des commentaires, je modifierai un peu les réponses précédentes
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 }));
})
)
);
J'inverse l'ordre, toujours en tirant AuthActions.loginSuccess(), puis this.matrixService.initClient(userName, password).
catchErrorn'a pas besoin d'être appelé deux fois, toute erreur générée par l'appel de service sera capturée dans l' catchErroropérateur le plus externe.