Reputation: 1821
I am struggling to grasp NgRx Effects.
Using the latest release, version 8, i have written the following effect which combines the observable with a promise and am struggling to grasp how to write it correctly.
Is this guaranteed to catch all possible errors?
authLogin$ = createEffect(() => this.actions$.pipe(
ofType(AuthActions.authLogin),
switchMap(async(action) => {
try {
const userState = await this.loginService.login(action.username, action.password);
return AuthActions.authSuccess(userState);
}
catch (error) {
return AuthActions.authLoginError({
error: error
});
}
})
),{ resubscribeOnError: false });
I am also not clear on whether or not i should be using the last bit of this configuration: { resubscribeOnError: false }
Does this mean subsequent execution will create an entirely new observable?
Is there a better approach?
Upvotes: 2
Views: 2615
Reputation: 2401
I'm not sure if this try catch
will catch all errors, cause I've only seen Promises with .then().catch()
, but why don't you convert this Promise to an Observable? It'd make your pipe
easier to write and to write properly.
Use your switchMap
to return an Observable from your Promise with
import {from} from 'rxjs';
...
switchMap(action => from(this.loginService.login(action.username, action.password)))
...
After that you can have your catchError
, an Observable operator from RxJs. You receive the error and a property called caught
, which is the source observable (from docs here). Where you can
...
catchError((err, caught$) => {
this.store.dispatch(new AuthActions.authLoginError({ error: error }));
return caught$;
})
...
The return caught$
is important cause you prevent your Effect from dying if an error occurs. You don't need to handle like that on NgRx 8, you could simple
...
catchError((err, caught$) => {
return of(new AuthActions.authLoginError({ error: error })));
})
...
But then you'd need your { resubscribeOnError: true }
(which is the default value). This is a feature that resubscribe on your Effect if you don't handle errors, once again preventing it from dying.
And then, after your catchError
, you can have a simple map
to return on success, like this
...
map(userState => new AuthActions.authSuccess(userState))
So, your finished code will look like this
authLogin$ = createEffect(() => this.actions$.pipe(
ofType(AuthActions.authLogin),
switchMap(action => from(this.loginService.login(action.username, action.password))),
catchError((err, caught$) => of(new AuthActions.authLoginError({ error: error })))),
map(userState => new AuthActions.authSuccess(userState))
)); // no resubscribeOnError since default value is true
I'd say this is a better approach since utilizes an Observable for your service call, you have operators separating responsibilities and makes NgRx happy.
Upvotes: 6