NgRx 9 brings us a brand new runtime check: strictActionWithinNgZone
. If enabled, this check will highlight any Action that is running outside of NgZone, enabling faster resolution of potential change detection issues.
Why enable strictActionWithinNgZone?
NgZone is used by Angular to manage change detection. If an Action is running outside of NgZone, any changes it causes, will not be reflected in the rendered output. i.e your user will have a stale view.
For example, if your action is updating a counter, but running outside of NgZone, then the rendered value will not change despite the value changing in your Typescript code. The user will see a stale value until another event triggers change detection.
This can lead to odd behaviour in your application which can be very difficult to debug. See my previous post which inspired this runtime check or this GitHub issue.
Change Detection: Getting in the (Angular) Zone!
Stephen Cooper ・ Jan 24 '20
The main challenge with this type of bug is identifying it in the first place. Often there are many components triggering change detection so that the buggy component never gets the chance to become stale. However, if you then decide to improve the performance of your application, by reducing change detection, you may suddenly have stale data to deal with!
This is where the strictActionWithinNgZone
runtime check helps you out. It immediately pinpoints actions that are running outside NgZone enabling you to fix these issues in development. In many cases, you may not have realised that you had a potential bug in your component!
How to use strictActionWithinNgZone
The strictActionWithinNgZone
check is opt-in, (there are valid use cases for running actions outside of NgZone). To enable the check, add it to your runtimeChecks
when importing your root StoreModule
.
@NgModule({
imports: [
StoreModule.forRoot(reducers, {
runtimeChecks: {
strictActionWithinNgZone: true
},
}),
],
})
export class AppModule {}
With this enabled, if there is an action, say [Counter] Increment
that is running outside of NgZone you will get the following error along with a link to the docs.
Action '[Counter] Increment' running outside NgZone.
What to do if you see the error?
Now that the action is identified you should locate the code where it was dispatched. I would recommend placing a breakpoint on the dispatch location and then trace the call stack back to the source event. It is worth noting that any Effects triggered by the action will also run outside of NgZone and all their subsequent actions too!
It is very important to trace back to the source event otherwise you may not completely remove the potential change detection issues.
The most likely cause of this will be an external component that is not Angular specific. In my experience, I have run into this where an app used jQuery to capture a Bootstrap event and another time within the error call of a web socket handler.
With the source event identified you can then wrap the call within the ngZone.run
callback to ensure that NgZone is aware of this event stack. With this change made the runtime check will no longer error as the action is now running within NgZone.
import { NgZone } from '@angular/core';
constructor(private store: Store<object>, private ngZone: NgZone) {}
update(){
this.ngZone.run(() => {
// Bring event back inside Angular's zone
this.store.dispatch(Increment());
});
}
}
NgRx runtime checks
As a reminder here are all the runtime checks that are available to help us avoid common pitfalls when writing our applications. NgRx ships with five built-in runtime checks and from v9 the immutability checks are on by default.
- Default On:
-
strictStateImmutability
: verifies that the state isn't mutated. -
strictActionImmutability
: verifies that actions aren't mutated
-
- Default Off:
-
strictStateSerializability
: verifies if the state is serializable -
strictActionSerializability
: verifies if the actions are serializable -
strictActionWithinNgZone
: verifies if actions are dispatched within NgZone
-
For all the other features in version 9 check out the official release post.
Top comments (0)