Error Handling
NGXS uses Angular's default
ErrorHandler
class, so if an action throws an error, Angular's ErrorHandler
is called. You can easily override this flow by providing your own handler like so:import { NgModule, ErrorHandler } from '@angular/core';
@Injectable()
export class MyErrorHandler implements ErrorHandler {
handleError(error: any) {
console.log('ERROR! ', error);
// Make sure to rethrow the error so Angular can pick it up
throw error;
}
}
@NgModule({
imports: [AppComponent],
providers: [
{
provide: ErrorHandler,
useClass: MyErrorHandler
}
]
})
export class AppModule {}
@Component({ ... })
class AppComponent {
@Select(state => state.count.number.value) count$: Observable<number>;
}
Let's take a look at the below example:
this.store.reset({}); // reset all states
The catch is that when resetting the entire state, the object will no longer have those deeply nested properties (
state.count.number.value
). Given the following code:const state = {};
function getCount() {
return state.count.number.value;
}
const count = getCount(); // will throw
RxJS will automatically complete the stream under the hood if any error is thrown.
You have to disable suppressing errors using the
suppressErrors
option:@NgModule({
imports: [
NgxsModule.forRoot([CountState], {
selectorOptions: {
suppressErrors: false // `true` by default
}
})
]
})
export class AppModule {}
This option allows to track errors and handle them.
@Component({ ... })
class AppComponent {
@Select(state => {
try {
return state.count.number.value;
} catch (error) {
console.log('error', error);
// throw error;
// Automatic unsubscription will occur if you use the `throw` statement here. Skip it if you don't want the stream to be completed on error.
}
})
count$: Observable<number>;
}
When you define an @Action you can handle error within the action and if you do so, the error will not propagate to Angular's global
ErrorHandler
, nor the dispatch
Observable. This applies to both sync and async types of Actions. @Action(HandledError)
handledError(ctx: StateContext<StateModel>) {
try {
// error is thrown
} catch (err) {
console.log('error catched inside @Action wont propagate to ErrorHandler or dispatch subscription')
}
}
If an unhandled exception is thrown inside an action, the error will be propagated to the
ErrorHandler
and you can also catch it subscribing to the dispatch
Observable. If you subscribe to the dispatch
Observable the error will be caught twice, once in the ErrorHandler and on your dispatch
handle. @Action(UnhandledError)
unhandledError(ctx: StateContext<StateModel>) {
// error is thrown
}
unhandled() {
this.store.dispatch(new UnhandledError()).pipe(
catchError(err => {
console.log('unhandled error on dispatch subscription')
return of('')
})
).subscribe();
}
It is recommended to handle errors within
@Action
and update state to reflect the error, which you can later select to display where required.Last modified 1yr ago