ngRx/Store and 5 silly mistakes
Tags: ngrx, angular
Published: 2020-03-03 13:46:24

---
title: ngRx/Store and 5 silly mistakes
published: true
date: 2020-03-03 13:02:02 UTC
tags: ngrx,angular
canonical_url: https://itnext.io/ngrx-store-and-5-silly-mistakes-780ae2f961d0
cover_image: https://cdn-images-1.medium.com/max/1024/1*p-m8joe-7CQY9aXyoc2K3w.jpeg
---

_In this article, I will tell you how to avoid simple pitfalls while working with ngRx to improve your family-work balance:-)_

#### Introduction

If you work with Angular you definitely know about the most popular state management system for Angular applications [**ngRx/Store**](https://ngrx.io/).

Let's recall what it is to be on the same page:

> **@ngrx/store**

> … is RxJS powered state management for Angular applications, inspired by Redux. Store is a controlled state container designed to help write performant, consistent applications on top of Angular.

Here is the flow diagram from official documentation describing how it works:

![](https://cdn-images-1.medium.com/max/1024/0*F1zvhLBSOjf9HVRa.png)

Components send **Actions** that is an object with a mandatory property _type_ and optionally other properties with data to be stored to the central object — a Store. Actions are being handled by **_reducers_** _,_ a special functions that make data from actions and put them to Store (or modify Store). Other components can subscribe to Store updates (to a specific part of the Store) with **selectors** (actually selectors determines which part of the Store updates you want to monitor). In simple cases, selectors receive state object as an argument and return you some property of the state object:

```
(state) => state.prop1
```

Before I start to keep your time let's review the simplest example. Not to re-invent the bicycle I will use the simplified example from the [official doc](https://ngrx.io/guide/store).

We will create a Store with counter value, and action/reducer that increases that counter value.

Let's create an action:

```ts
// src/app/counter.actions.ts

import { createAction } from '@ngrx/store';

export const increment = createAction('[Counter Component] Increment');
```

Reducer:

```ts
//src/app/counter.reducer.ts

import { createReducer, on } from '@ngrx/store';
import { increment } from './counter.actions';

export const initialState = 0;
const _counterReducer = createReducer(initialState,
   on(increment, state => state + 1)
);

export function counterReducer(state, action) {
   return _counterReducer(state, action);
}
```

Add StoreModule module to app.module.ts

```ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';

import { StoreModule } from '@ngrx/store';

import { counterReducer } from './counter.reducer';

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    StoreModule.forRoot({ count: counterReducer })
  ],
  providers: [],
  bootstrap: [AppComponent],
})

export class AppModule {}
```

You can see that we specify our reducer in this line

```ts
StoreModule.forRoot({ count: counterReducer })
```

To read count value we just need to use [_select_](https://ngrx.io/api/store/select) function in a component:

```ts
// in some component
import { Store, select } from '@ngrx/store'
...

constructor(private store: Store<{ count: number }>) {

this.count$ = store.pipe(select('count')); 
// now we have observable that will emit values on each count update

// old school approach
//this.count$ = store.pipe( select(state => state.count));

}
```

What if we don't want to keep count in the main app module?  
We can put it to a feature module.

```ts
@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    StoreModule.forRoot({}),
    StoreModule.forFeature('featureName', { count: counterReducer })
  ],
  providers: [],
  bootstrap: [AppComponent],
})

export class AppModule {}
```

Now our selector to grab the value from feature-branch of the Store state will be:

```ts
// count.selectors.ts
export const selectFeature = createFeatureSelector<FeatureState>('featureName');

export const countSelector = createSelector(selectFeature, (state) => state.count);


// And in some component
this.count$ = store.pipe( **select** (countSelector));
```

Now let's check how all this works:

![](https://cdn-images-1.medium.com/max/834/1*m_qx6oiKiKYvBCxghwtqJg.gif)<figcaption>One component increments state.count, another component displays state value.</figcaption>

All our actions and Store state changes we can observe with nice Chrome plugin: [Redux DevTools](https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd?hl=ru):  
1. Install a plugin in Chome  
2. install [@ngrx/store-devtools](https://ngrx.io/api/store-devtools) module to your Angular app:  
 —  **ng add @ngrx/store-devtools**   
- Or **_npm i @ngrx/store-devtools_** (in that case you should add StoreDevtoolsModule to AppModule manually)

3. monitor your Store in Chrome Dev Tools (Redux tab)

![](https://cdn-images-1.medium.com/max/1024/1*HF8QV6G3oodF_PUilE4OTw.gif)

Simple, right?

At that place, you may ask yourself why do we need an article that just represents the official documentation example? Because even with these simple flows you can spend hours on debugging if something doesn't work as expected.

**I revealed 5 often mistakes in my (and my fellow developers) practice.**

#### **#1. Redux-DevTools doesn't display undefined props in actions**

Say we have an action that sends not the only type of message but also some additional info:

```ts
{
 type: SOME_TYPE,
 value: this.someProp
}
```

For that purpose lets modify a bit our code:

```ts
// counter.actions.ts
...
export const increment = createAction('[Counter Component] Increment', props<{value: number}>());

// counter.reducer.ts
const counterReducerFunc = createReducer(initialState,
  on(increment, (state, {value}) => state + 1 + value)
);

//app.component.ts
public value;
...

increment() {
// provide additional value to actionCreator function this.store.dispatch(increment({value: this.value})); 
}
```

Now our reducer should increase state value by 1 and add _value._

But, something goes wrong and you want to debug the actions in Redux Dev Tools.

![](https://cdn-images-1.medium.com/max/1024/1*IJ4-k05xAchgK_0dfYz3rg.gif)<figcaption>Debugging issue</figcaption>

Ok, _count_ got NAN value, this is not correct. And why don't we see _value_ prop in action tab content in ReduxDevTools? Only _type_ field is present.

The answer is that **a)** we forgot to assign some number to _value_ property, **b)**  **_Chrome plugins cannot get undefined values_** since it cannot be stringified.

Let's assign _value_ with 0 **_._**

```ts
//app.component.ts
public value = 0; // or other number value
```

Now we can observe this prop in ReduxDevTools:

![](https://cdn-images-1.medium.com/max/1024/1*zuMWdDe3s6tMJRy-cS2grw.gif)

I spend an hour to reveal it. Maybe you will waste less time after reading this:)

You can take a look at code in [this branch of the article GitHub repo](https://github.com/kievsash/ngrx-store-and5sillyMistakes/tree/pitfall_1_ReduxDevTools_Doesnt_display_undefined). Or check it in a [ng-run.com playground](https://ng-run.com/edit/Zi5H99cHsvPsoDHFpble).

**Take away:** better to use **null** if you need to specify empty value since null can be stringified and can be shown in ReduxDevTools.

#### **#2. StoreDevModule may slow down the app**

Once upon a time, I had a big list of objects in a Store. And some user operations modified data on the specific Action type and put them back to Store and then components displayed that data.

What our testers observed that starting from a few hundreds of items in a list each user operation caused small but noticeable UI update lags. And this was not rendering but JS issue.

After checking with ChromeDevTools on Performance tab (you can read more about it [here](https://developers.google.com/web/tools/chrome-devtools/rendering-tools)) I got this picture:

![](https://cdn-images-1.medium.com/max/562/1*fO3bfV3jShQmUiRHPxc8Cg.png)<figcaption>7.8% of Javascript activity is grabbed by stringify function</figcaption>

Do you remember why it may happen? Yes, because we send data to our ReduxDevTools plugin to be able to monitor Store Actions and state.

Since we added StoreDevToolsModule manually to the AppModule — we missed an option to turn it off for prod builds:

```ts
imports: [
  StoreModule.forRoot({}),
  StoreModule.forFeature(featureKey, {items: itemsReducer}),
  BrowserModule,
  StoreDevtoolsModule.instrument({ maxAge: 25, logOnly: environment.production }), // missed logOnly option
  EffectsModule.forRoot([AppEffects])
],
```

After I added it — UI started to feel much better:-)

**Takeaway:** do not forget **logOnly** option when you use StoreDevtoolsModule to monitor your ngrx/Store activities. Actually, if you install it with **ng add @ngrx/store-devtools** then this option will be added automatically. You can read more about _logOnly_ [here](https://stackoverflow.com/a/49106637/6528560).

You can play with the code [in GitHub repo branch](https://github.com/kievsash/ngrx-store-and5sillyMistakes/tree/pitfall_2_StoreDevtoolsModule_slow_down). Or start this branch on [ng-run.com](https://ng-run.com/) Angular playground by [Alexey Zuev](https://medium.com/u/d59a9e801370). For that just copy GitHub branch link and add ng-run.com/github/<yourlink> like this:

```
Branch link:
https://github.com/kievsash/ngrx-store-and5sillyMistakes/tree/pitfall_2_StoreDevtoolsModule_slow_down

Now let's start it on ng-run.com by this link (copy it to browser address bar):

https://ng-run.com/github/kievsash/ngrx-store-and5sillyMistakes/tree/pitfall_2_StoreDevtoolsModule_slow_down
```

**#3. You import feature module but it doesn't work**

**a)** Ok, So you have nice feature Angular module where you put:

```ts
// feature.module.ts

...

imports: [
   StoreModule.forFeature(featureKey, {items: itemsReducer}),
...
```

You expect it should work when you added it to app.module.ts AppModule imports. But… it doesn't) You open a ChromeDevTools console and see:

![](https://cdn-images-1.medium.com/max/717/1*HHzO9DIpC3hu77-mVP1zSw.png)

Ok, so we go to [ngrx/platform GitHub repo](https://github.com/ngrx/platform/search?q=ReducerManager&unscoped_q=ReducerManager) and search for '_ReducerManager_' entity. And see that it is provided as REDUCER\_MANAGER\_PROVIDERS by StoreModule.forRoot(…) call [here](https://github.com/ngrx/platform/blob/8.6.0/modules/store/src/store_module.ts#L164).  
Answer is obvisous: we forgot to include StoreModule.forRoot({}) in out AppModule.

```ts
// app.module.ts
imports: [
  StoreModule.forRoot({}),
  StoreModule.forFeature(featureKey, {items: itemsReducer}),
```

Now it works well.

**_b)_** _I found one more interesting behavior but with StoreDevtoolsModule_

Ok, so you added it to AppModule:

```ts
imports: [
  StoreDevtoolsModule.instrument({ maxAge: 25, logOnly: environment.production }),
  StoreModule.forRoot({}),
  StoreModule.forFeature(featureKey, {items: itemsReducer}),
```

But when you open Redux tab in ChromeDevTools you see this:

![](https://cdn-images-1.medium.com/max/737/1*Ska_gpHACxP_7o8O4c0VLA.png)<figcaption>No Store found.</figcaption>

Why??

Because I just put StoreDevtoolsModule in _imports_ array BEFORE StoreModule.forRoot. So it seems like Angular tries to instantiate it before any Store is created. Just put StoreDevtoolsModule AFTER StoreModule.forRoot in AppModule decorator _imports_ array to fix the issue.

```ts
imports: [
  StoreModule.forFeature(featureKey, {items: itemsReducer}),
  StoreModule.forRoot({}),
  StoreDevtoolsModule.instrument({ maxAge: 25, logOnly: environment.production }),
```

Now it works good:

![](https://cdn-images-1.medium.com/max/714/1*1ezAkljV6o4xcjknLBzOlw.png)

Interesting that in Angular 9 putting _StoreModule.forFeature_ BEFORE StoreModule.forRoot doesn't create any [issue](https://github.com/ngrx/platform/issues/400).

You can find the code to play with [here](https://github.com/kievsash/ngrx-store-and5sillyMistakes/tree/pitfall_3_StoreDevtoolsModule_before_StoreModule.forRoot).

**#4. Exported reducer function is necessary as function calls are not supported by the AOT compiler (in Angular 8).**

The title of this pitfall sounds not clear but actually it is very simple. You have reducer:

```ts
export const counterReducer = createReducer(initialState,
  on(increment, state => state + 1),
  on(decrement, state => state - 1),
  on(reset, state => 0),
);

@NgModule({
  declarations: [],
  imports: [
    StoreModule.forRoot({ count: counterReducer })
  ],
  providers: [],
})
export class CounterStateModule { }
```

And it works quite well…until we try to build the production code:

```
ERROR in Error during template compile of 'CounterStateModule'
  Function calls are not supported in decorators but 'createReducer' was called in 'counterReducer'
    'counterReducer' calls 'createReducer' at app/counter.state.ts
```

This is a well-know issue, you can read more about it [here](https://angular.io/guide/aot-metadata-errors#function-calls-are-not-supported).

Fortunately, when I tested it on Angular 9 project with Ivy (ngRx/Store 8.6) — it was already solved! You can read more details in this [issue](https://github.com/ngrx/platform/issues/2241).

You can check the code [here](https://github.com/kievsash/ngrx-store-and5sillyMistakes/tree/pitfall4_no_need_to_export_function_for_reducer).

**Takeaway:** [update to Angular 9](https://angular.io/guide/updating-to-version-9) 😎

**#5. Action creator is a function but if you forget to put parentheses — ngRx keeps silence.**

Here is a possible pitfall reproduce code:

```ts
constructor(private store: Store<{ count: number }>) {
}

selectAll() {
  this.store.dispatch(select);//should be select() but no type error
}
unselectAll() {
  this.store.dispatch(unselect()); // correct
}
```

Typescript will not help you here. But fortunately, you will find a hint in ChromeDevTools console:

![](https://cdn-images-1.medium.com/max/713/1*M2RdZeTXQl0fbSOR5Xmv6g.png)

**Takeaway:** Do not put all eggs in typescript basket 🎓 Sometimes it may not help you.

#### Conclusion

Ok, so what we have learned in this article?

1. Use **null** instead of **undefined** as _noValue_ to be able to observe it in ReduxDevTools Chrome plugin.
2. StoreDevModule may slow down the app. To prevent it — set _logOnly_ option as _true._
3. Do not forget to put StoreModule.forRoot({}) in AppModule when you connect other ngrx/Store feature modules.
4. Exported reducer function is not necessary in Angular 9.
5. Do not forget to put parentheses in your call action creator function.

Now you can spend more time with your family but not in debugging sessions⛷

Let’s keep in touch on [**Twitter**](https://twitter.com/El_Extremal)!

> BTW. I started a video tutorial series “[**Angular can waste your time**](https://www.youtube.com/watch?v=HI5f6naJdJ8&list=PLNadw4d8-KMVSOffiYBuOlzvF38sO9pdu&utm_content=educational&utm_campaign=2019-11-13&utm_source=email-sendgrid&utm_term=8565702&utm_medium=2586716)” on Youtube. There I will be publishing videos about resolving tricky cases with Angular and RxJS. [**Take a look!**](https://www.youtube.com/watch?v=HI5f6naJdJ8&list=PLNadw4d8-KMVSOffiYBuOlzvF38sO9pdu&utm_content=educational&utm_campaign=2019-11-13&utm_source=email-sendgrid&utm_term=8565702&utm_medium=2586716)


![](https://cdn-images-1.medium.com/max/594/0*_mYOWVBC882P8ClS.png)

Cheers!

* * *