Is it possible to make mistakes inside ngrx effects without ending the Observable stream?

Is it possible to use throw with an Error object inside ngrx-effects threads without ending the stream?

I read these wonderful answers about why the thread is being killed causing an error:

@ngrx The effect does not start a second time

Ngrx error handling

https://github.com/ngrx/platform/issues/646

My question is that I am implementing Angular ErrorHandler to catch errors if I am going to use this with ngrx effects.

 @Effect() loginUserEffect: Observable<loginActions.Actions> = this.actions$ .ofType(loginActions.LOGIN_USER) .map((action: loginActions.LoginUser) => action.payload) .mergeMap(payload => { return this.loginService .authenticate(payload) .map(response => new loginActions.LoginUserSuccess(response)) .catch((error: HttpErrorResponse) => of(new loginActions.LoginUserFailure(error)) ) }) @Effect({ dispatch: false }) loginUserEffectSuccess$ = this.actions$ .ofType(loginActions.LOGIN_USER_SUCCESS) .do(() => this.router.navigate(['/account-home'])) @Effect({ dispatch: false }) loginUserEffectFailure$ = this.actions$ .ofType(loginActions.LOGIN_USER_FAILURE) .map((action: loginActions.LoginUserFailure) => { throw action.payload // Stream completes }) 

I suppose that I could create some way to deal with errors that are not related to throwing something, but I wanted to make sure that I need to go along this route or if there is a way to maintain their peaceful coexistence.

Currently in my class that implements ErrorHander , I have this:

 @Injectable() export class GlobalErrorHandler implements ErrorHandler { private messagesService: MessagesService private router: Router constructor( private injector: Injector, // DI workaround (https://stackoverflow.com/a/41585902) private errorLoggerService: ErrorLoggerService ) { // DI workaround (https://stackoverflow.com/a/41585902) setTimeout(() => (this.messagesService = injector.get(MessagesService))) setTimeout(() => (this.router = injector.get(Router))) } handleError(error) { if (error instanceof HttpErrorResponse) { this.handleServerError(error) } else if (error instanceof ClientError) { this.handleClientError(error) } else { this.handleUnexpectedError(error) } } 

This means that I just throw errors and they are handled based on type

+1
source share
2 answers

If you want to throw an error that will not be detected by an observable, and instead be reported to the global error handler, you will throw an error from outside the observable call stack.

You can do something like this:

 @Effect({ dispatch: false }) loginUserEffectFailure$ = this.actions$ .ofType(loginActions.LOGIN_USER_FAILURE) .do(action => setTimeout(() => { throw action.payload; }, 0)) }) 

However, since your effects are in a class that already uses the Angular DI mechanism, I would suggest you introduce GlobalErrorHandler and call it directly.

Without setTimeout calls, I think it would be simpler and easier to test.

+1
source

As a result, I created the "Error" action:

 @Effect() loginUserEffectFailure$: Observable< errorsActions.Actions > = this.actions$ .ofType(loginActions.LOGIN_USER_FAILURE) .map( (action: loginActions.LoginUserFailure) => new errorsActions.Error(action.payload) ) 

and with a call the error handler in a special effect:

 @Effect({ dispatch: false }) errorEffect$ = this.actions$ .ofType(errorsActions.ERROR) .map((action: errorsActions.Error) => this.clientErrorHandler.handleError(action.payload) ) 

I left the global error handler only to detect and report unexpected exceptions.

+1
source

Source: https://habr.com/ru/post/1272691/


All Articles