Introduction to NGXS, state management pattern + library for Angular

Reading Time: 3 minutes

Ngxs is a state management pattern for the Angular framework. It acts as a single source of truth for our application. Ngxs is very simple and easily implementable. It reduce  lots of boilerplate code . It is a replacement for Ngrx. In Ngrx we are creating state, action, reducer, and effects but in Ngxs, we are creating only state and actions instead of all of this.  Like Ngrx, Ngxs is also asynchronous and when we dispatch any action we can get a response back.

When we learn anything then one Question always arrives in our mind.

Why?

Why do we use Ngxs?

Simple:

We already know, Ngxs reduce a lot of boilerplate code, it makes things as simple as possible and we don’t need to be familiar with rxjs library.

Dependency Injection ( DI ):

Dependency injection is a core feature of Angular. We create a single instance of a class that gives better performance and many more things. Ngsx allows us to use DI. We can create a singleton instance and use it everywhere.

Promises:

Observables are good but they are not silver bullets. Sometimes we need to use promises. Ngxs allow us to return from the Action method.

Pillars of Ngxs:

Ngxs has 4 pillars in which ngxs work

  1. Store: Global state container
  2. Action: classes that describe actions and metadata
  3. State: state is the definition of class
  4. Selects: selectors slices state 

Let us learn every pillar one by one:

Install dependencies :

  • run command ng add @ngxs/store 
  • ng add @ngxs/logger-plugin
  • ng add @ngxs/devtools-plugin

Store:

Store is a global state manager, we are importing NgxModule from @ngxs/store.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HomeComponent } from './_ui/home/home.component';
import { NgxsModule } from '@ngxs/store';
import {TutorialState} from './_store/States/tutorial.state';
import { NgxsLoggerPluginModule } from '@ngxs/logger-plugin';
import { NgxsReduxDevtoolsPluginModule } from '@ngxs/devtools-plugin';
import {ReactiveFormsModule} from '@angular/forms';
 
@NgModule({
 declarations: [
   AppComponent,
   HomeComponent
 ],
 imports: [
   BrowserModule,
   AppRoutingModule,
   NgxsModule.forRoot([TutorialState]),
   NgxsLoggerPluginModule.forRoot(),
   NgxsReduxDevtoolsPluginModule.forRoot(),
   ReactiveFormsModule,
 
 
 ],
 providers: [],
 bootstrap: [AppComponent]
})
export class AppModule { }

Let’s  create Actions :

We are now going to create actions that we dispatch, each action containing a  type field and payload.

import { Tutorial } from "src/app/_models/tutorial.interface";
 
export class AddTutorial {
 static readonly type = '[Tutorial] Add';
 
 constructor(public payload: Tutorial){}
}
 
export class RemoveTutorial {
 static readonly type = '[Tutorial] Remove';
 
 constructor(public payload: string) {}
}

Now the most important thing in ngxs is to create state.

Let’s  create state  now:

State: state are classes along with decorator that describe the metadata and action.

We can define state as:

 
@State<TutorialStateModel>({
 name: 'tutorial',
 defaults: {
   tutorial: []
 }
})

name in state is used to select the state, or we can say that its specific state and default in the state describe the state’s default data.

import {State , Action , StateContext, Selector} from '@ngxs/store';
import * as TutorialAction from '../Actions/tutorial.action';
import { Tutorial } from '../../_models/tutorial.interface';
 
 
export class  TutorialStateModel {
 tutorial: Tutorial[];
}
 
@State<TutorialStateModel>({
 name: 'tutorial',
 defaults: {
   tutorial: []
 }
})
 
export class TutorialState {
 
 @Selector()
 static getTutorial(state: TutorialStateModel): Tutorial[]{
   return state.tutorial;
 }
 
 
 @Action(TutorialAction.AddTutorial)
 get({ getState, patchState}: StateContext<TutorialStateModel>, {payload}: TutorialAction.AddTutorial): any{
   const state = getState();
   patchState({ tutorial: [...state.tutorial , payload]
   });
 }
 
 @Action(TutorialAction.RemoveTutorial)
 remove({ getState, patchState}: StateContext<TutorialStateModel>, {payload}: TutorialAction.RemoveTutorial): any{
   patchState({ tutorial: getState().tutorial.filter(tutorial => tutorial.name !== payload)
   });
 }
}

Select: 

Select is a function that allows us to select a specific state or specific part of the state. Specific parts of data from the store are selected by using the @Select decorator.

import { Component, OnInit } from '@angular/core';
import { Select, Store } from '@ngxs/store';
import { Observable } from 'rxjs';
import { Tutorial } from 'src/app/_models/tutorial.interface';
import { AddTutorial } from 'src/app/_store/Actions/tutorial.action';
import { TutorialState } from 'src/app/_store/Satates/tutorial.state';
 
@Component({
 selector: 'app-home',
 templateUrl: './home.component.html',
 styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
// selecting state
@Select(TutorialState.getTutorial)tutorials$: Observable<Tutorial[]>;
 constructor(private store: Store) {
 }
 
 addTutorial(name: string, url: string): void{
   this.store.dispatch(new AddTutorial({  name,  url})); // dispatch an 
                                                          //action
 }
 
}

Conclusion:

In this post we learn about ngxs, In ngxs how we can create state and action, and how we can dispatch action and select a state. Now we can easily understand why NGXS is replacement of NGRX.  Ngxs reduce boilerplate code and help us to manage the state of our application easily.

Leave a Reply