Enterprise Angular Applications with NgRx and Nx
  • Introduction
  • Introduction
    • Introduction
    • Course Description
    • Resources
    • 0 - Environment Setup
    • 1a - Brief Introduction To Angular
    • 1b - Brief Introduction To Angular
    • 1c - Brief Introduction To Angular
    • 2 - Creating an Nx Workspace
    • 3 - Generating components and Nx lib
    • 4 - Add JSON server
    • 5 - Angular Services
    • 6 - Angular Material
    • 7 - Reactive Forms
    • 8 - Layout Lib and BehaviorSubjects
    • 9 - Route Guards and Products Lib
    • 10 - NgRx Introduction
    • 11 - Adding NgRx to Nx App
    • 12 - Strong Typing the State and Actions
    • 13 - NgRx Effects
    • 14 - NgRx Selectors
    • 15 - Add Products NgRx Feature Module
    • 16 - Entity State Adapter
    • 17 - Router Store
    • 18 - Deploying An Nx Monorepo
Powered by GitBook
On this page
  • 1. Presentation
  • 2. Install redux dev tools chrome extension
  • 3. Simple Counter Demo
  • a) Make a new empty Angular CLI Project
  • b) Add NgRx to the app
  • c) Add a counter.reducer.ts fill to a new state folder in the app
  • d) Register the reducer and NgRx in the App module
  • e) Add the HTML to the App component
  • f) Add App component logic
  • g) Adding action creators
  • h) Adding action State interfaces
  • i) Add global State interface
  • j) Use state interface in app component
  1. Introduction

10 - NgRx Introduction

Previous9 - Route Guards and Products LibNext11 - Adding NgRx to Nx App

Last updated 3 years ago

1. Presentation

Presentation: NgRx

2. Install redux dev tools chrome extension

3. Simple Counter Demo

a) Make a new empty Angular CLI Project

We will make a simple NgRx demo app first before getting deep into it with Nx which will scaffold out an opinionated abstracted version.

cd workshop
ng new ngrx-counter-demo
cd ngrx-counter-demo
code .

b) Add NgRx to the app

npm install @ngrx/store @ngrx/store-devtools

c) Add a counter.reducer.ts fill to a new state folder in the app

src/app/state/counter.reducer.ts
export function counterReducer(state, action) {
  on('INCREMENT', state => state + 1),
  on('DECREMENT', state => state - 1),
  on(reset, state => 0),
);

d) Register the reducer and NgRx in the App module

src/app/app.module.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 './state/counter.reducer';
import { StoreDevtoolsModule} from '@ngrx/store-devtools';

@NgModule({
  declarations: [
    AppComponent,
  ],
  imports: [
    BrowserModule,
    StoreModule.forRoot({ counter: counterReducer }),
    StoreDevtoolsModule.instrument({})
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

e) Add the HTML to the App component

src/app/app.component.html
<button (click)="increment()">Increment</button>
<div>Current Count: {{ count$ | async }}</div>
<button (click)="decrement()">Decrement</button>

f) Add App component logic

Note: changeDetection: ChangeDetectionStrategy.OnPush to avoid issue with change detection.

src/app/app.component.ts
import { Component, ChangeDetectionStrategy } from '@angular/core';
import { select, Store } from '@ngrx/store';
import { Observable } from 'rxjs';
​
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class AppComponent {
  count$: Observable<number>;
​
  constructor(private store: Store<any>) {
    this.count$ = store.pipe(select('counter'));
  }
​
  increment() {
    this.store.dispatch({ type: 'INCREMENT' });
  }
​
  decrement() {
    this.store.dispatch({ type: 'DECREMENT' });
  }
​
}

g) Adding action creators

At this point we have no strong types for our actions or our state tree, let's fix that.

  • Add a file to the state folder called counter.actions.ts

src/app/state/counter.actions.ts
import { Action } from '@ngrx/store';

export enum CounterActionTypes {
    Increment = '[Counter Page] Increment',
    Decrement = '[Counter Page] Decrement'
}

export const increment = createAction(CounterActionTypes.Increment);

export const decrement = createAction(CounterActionTypes.Decrement);

h) Adding action State interfaces

  • In the top of the reducer file add a CounterState interface and use it as our new action types in the reducer.

src/app/state/counter.reducer.ts
import { CounterActions, CounterActionTypes } from 'src/app/state/counter.actions';

export interface CounterState {
  count: number;
}

export const initialState: CounterState = {
  count: 0
};

export function counterReducer(state = initialState, action: CounterActions) {
  switch (action.type) {
    case CounterActionTypes.Increment:
      return {
        count: state.count + 1
      };

    case CounterActionTypes.Decrement:
      return {
        count: state.count - 1
      };

    default:
      return state;
  }
}

i) Add global State interface

This is useful to be able to type your injected store and select state.

src/app/state/appState.ts
import { CounterState } from 'src/app/state/counter.reducer';

export interface AppState {
    counter: CounterState;
}

j) Use state interface in app component

src/app/app.component.ts
import { Component, ChangeDetectionStrategy } from '@angular/core';
import { select, Store } from '@ngrx/store';
import { Observable } from 'rxjs';
import { Increment, Decrement } from 'src/app/state/counter.actions';
import { AppState } from 'src/app/state/appState';                 // Added

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class AppComponent {
  count$: Observable<number>;
​
  constructor(private store: Store<AppState>) {                      // Added
    this.count$ = store.pipe(select(state => state.counter.count));  // Added
  }
​
  increment() {
    this.store.dispatch(new Increment());
  }
​
  decrement() {
    this.store.dispatch(new Decrement());
  }
​
}
https://docs.google.com/presentation/d/1MknPww1MdwzreFvDh086TzqaB5yyQga0PaoRR9bgCXs/edit?usp=sharing
https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd?hl=en