Introduction to state management with Ngrx and Angular

Introduction 🚩 :

What is State Management 📝

Types of State 📰

State Management 📰:

Solution :

Benefits of State Management 🔥 💥 :

Use cases for state management : 💶 💶

How Data Flows Without State Management with Angular ❓

Available tooling for State Management with Angular ✒️ ✂️:

Native Rxjs ☝️ :

AKITA ↖️:

NGXS ⚓:

Ngrx ✈️ ✈️ :

What is Ngrx?

Why we will choose Ngrx ⁉️

Ngrx Core-Concepts :

source : https://ngrx.io/guide/store

Store :

State :

Actions:

Reducers:

Effects:

Selectors :

Cons of Ngrx 🚫 ❌ :

Application Example (counter-app)💻 :

1) Generate an Angular App with Angular-CLI :

ng new ngrx-poc --style=scss --routing=false

2) Open your project with Vscode :

code .

3) Run the App :

cd ngrx-pocnpm start

4) Install NgRx and Tools:

npm install @ngrx/store --savenpm install @ngrx/effects --savenpm install @ngrx/store-devtools --save

5) Define your state

export interface CounterState {counter: number;}export const initialState: CounterState = {counter: 4};

6) Define our actions

import { createAction, props } from '@ngrx/store';export const increment = createAction('increment');export const decrement = createAction('decrement');export const reset = createAction('reset');export const incrementAction = createAction('[Counter] Increment',props<{ count: number }>());

7) Define our reducer

import { Action, createReducer, on, State } from '@ngrx/store';import { CounterState, initialState } from './counter.state';import * as CounterActions from './counter.actions';const counterReducer = createReducer(initialState,on(CounterActions.increment, (state) => {return {...state,counter: state.counter + 2,};}),on(CounterActions.decrement, (state) => {return {...state,counter: state.counter - 2,};}),on(CounterActions.reset, (state) => {return {...state,counter: 0,};}));export function reducer(state: CounterState | undefined, action: Action) {return counterReducer(state, action);}

8) Selectors for store data selection

import { createFeatureSelector, createSelector } from '@ngrx/store';import { CounterState } from './counter.state';export const COUNTER_STATE_NAME = 'counter';export const selectCounter =createFeatureSelector<CounterState>(COUNTER_STATE_NAME);export const getCount = createSelector(selectCounter,(state: CounterState) => state.counter);

9) Add the store and reducer to app. module

@NgModule({declarations: [AppComponent],imports: [BrowserModule,StoreModule.forFeature(COUNTER_STATE_NAME,reducer)],providers: [],bootstrap: [AppComponent]})export class AppModule { }

10) Generate counter component and child components

10.1: Generate the counter component

ng g c counter

10.2: Generate the counter-buttons component

ng g c counter-buttons 
<div><button class="btn btn-primary" (click)="onIncrement()">Increment</button>&nbsp;<button class="btn btn-warning" (click)="onDecrement()">Decrement</button>&nbsp;<button class="btn btn-info" (click)="onReset()">Reset</button></div>
import { Component, OnInit } from '@angular/core';import { Store } from '@ngrx/store';import { decrement, increment, reset } from '../store/counter.actions';import { CounterState } from '../store/counter.state';@Component({selector: 'app-counter-buttons',templateUrl: './counter-buttons.component.html',styleUrls: ['./counter-buttons.component.scss']})export class CounterButtonsComponent implements OnInit {constructor(private store: Store<CounterState>) { }ngOnInit(): void {}onIncrement(){this.store.dispatch(increment())}onDecrement(){this.store.dispatch(decrement())}onReset(){this.store.dispatch(reset())}}

11) component counter-output to output the data

import { Component, OnInit } from '@angular/core';import { Store } from '@ngrx/store';import { Observable } from 'rxjs';import { getCount } from '../store/counter.selector';import { CounterState } from '../store/counter.state';@Component({selector: 'app-counter-output',templateUrl: './counter-output.component.html',styleUrls: ['./counter-output.component.scss']})export class CounterOutputComponent implements OnInit {counter$ : Observable<number>constructor(private store: Store<CounterState>) {}ngOnInit(): void {this.counter$ = this.store.select(getCount)}}
<div><h3>Counter is: {{ counter$ | async }}</h3></div>

12) counter container component final code :

<div class="row"><div class="col-md-12"><div class="my-6"><app-counter-output></app-counter-output></div><div class="my-6"><app-counter-buttons></app-counter-buttons></div></div></div>
<div><app-counter></app-counter></div>

Run the App:

npm start

Final output :

Appendix 📘 📙 :

Angular ngrx-data :

@ngrx/entity

@ngrx/router-store:

@ngrx/schematics

@ngrx/store-devtools :

Example Ngrx devtools screenshot

ngrx-store-logger:

ngrx-store-localstorage:

Nx :

References 📓 📕 :

Conclusion ❤️:

<script>alert('try your best')</script>