NGRX in Angular

Hamid Hassani
Mobiroller Tech
Published in
6 min readApr 25, 2023

Have you ever felt your project is getting tedious cause you have to send the same requests in different components, or you need the same data in different places and you are injecting your services again and again in order to fetch the same data, therefore, these actions lead your components get complicated, Have you ever thought you need to manage all these stuff in a centralized manner and delegate the responsibility of manipulating data to a specific mechanism, I bet if you developed a medium or large-size project you have came up with these questions.

So what would be the solution in such cases? Frankly, there are enormous workarounds for this but believe me, the best option is using state management libraries such as NGRX, NGXX, Akita, etc. Among these libraries, I prefer to use NGRX in my project because of the better community and support by its team.
Long story short, we want to use NGRX in our project in terms of having state management but what do we mean by the state?
In fact, We mean a global variable that we can update and read its data wherever we want.

So we want to manage the state with a solution in our project, but how? Managing the state in an Angular application can be a challenging task, especially as the application grows in complexity. Stay stunned, In this article, we will take a closer look at NgRx and its features, and see how it can help you manage state in your Angular application.

How does NgRx work?

In the Angular project which uses NGRX, there is something called state which is a global/shared data that is accessible through all components. By the way you can define feature state, Let’s suppose you have different features in your project such as products, orders, categories, etc and we want to define a state for orders feature. we have two pages related to orders which are order list and order details pages. If we wanted to manage the order feature state we are supposed to define a class like this


export class OrderFeatureState {
list: any[]; // this will use in order list page
order: any; // this will use in order details page
}

Actions in NGRX

The state cannot be directly modified by components in the application. Instead, components can dispatch actions. but what are actions? is that your question? All right, Actions in NgRx are events/commands that you want to notify your store. If you want to make any change in store you have to dispatch an action and this would be the first step of the change process. Actions can be any events that are happing in your project like updating a product, creating a new brand, deleting a category, etc. Actions are dispatched by components using the Store.dispatch() method. Take a look at the below example:


import { ChangeDetectorRef, Component, OnInit, ViewChild } from '@angular/core';
import { Store } from '@ngrx/store';

@Component({
selector: 'app-applications-list',
templateUrl: './applications-list.component.html',
styleUrls: ['./applications-list.component.scss'],
})
export class ApplicationsListComponent implements OnInit {
constructor(private readonly _store: Store) {}

public ngOnInit(): void {
this._store.dispatch(loadListOfApplications());
}
}

What is Reducer then?

Reducers in NgRx are pure functions that take the current state and an action and return a new state. it means that are supposed to modify the state based on an action, they listen to the actions that dispatching through the project when a specific action happened they modify the state! (you can think of them like they are events or commands in the CQRS pattern)

export const OrderFeatureReducer = createReducer(
initialState,
on(loadListOfApplications, (state, { response }) => ({
...state,
list: response,
}))

What is the Effect of NGRX?

Imagine you want to dispatch an action that is supposed to fetch data from an API, like fetching list of orders:

import { ChangeDetectorRef, Component, OnInit, ViewChild } from '@angular/core';
import { Store } from '@ngrx/store';

@Component({
selector: 'orders-list',
templateUrl: './orders-list.component.html',
styleUrls: ['./orders-list.component.scss'],
})
export class OrdersListComponent implements OnInit {
constructor(private readonly _store: Store) {}

public ngOnInit(): void {
this._store.dispatch(fetchListOfOrders());
}
}

Remember that I told you when an action is dispatched the reducers update the state, How can they understand how to change/update the state? Exactly, based on the action response, but what if the action response wasn’t ready to use? So if you want to make HTTP requests or update the browser’s location, log something, etc by an action that needs to wait you have to use an effect in order to handle the side effects and update the state.
So if you want to do something that there is no need to wait you directly update the state by reducer but if you wanted to do an action that needed to call API or asynchronous operations you have to use effect too.

So in a nutshell, Effects are defined as classes that implement the Effect interface. They listen for specific actions, and when they receive one, they perform some side effects and dispatch new actions to update the state of the application. Effects are typically used to manage asynchronous operations, such as loading data from a server.

import { Actions, createEffect, ofType } from '@ngrx/effects';

@Injectable({
providedIn: 'root'
})
export class OrderFeatureEffects {
public fetchListOfOrdersEffect$ = createEffect(() =>
this._actions$.pipe(
ofType(fetchListOfOrders),
switchMap((actions) => {
return this._orderService.getAllOrders().pipe(
map(
(response) =>
listOfOrdersFetchedSuccessfully({ response: response }),
catchError(() => EMPTY)
)
);
})
)
);

constructor(
private readonly _actions$: Actions,
private readonly _orderService: OrderService
) {}
}

Selectors

Selectors are functions that are used to query the state of the application. They are used to extract specific pieces of data from the store, and they can also be used to derive new data from the existing state. Selectors are memoized, which means that they cache the results of previous computations and only recompute when the input data changes.

Selectors can be used to improve the performance of an application by reducing the number of times that the application needs to recompute data. They can also be used to simplify the logic of components by encapsulating complex data transformations.

export const orderState =
createFeatureSelector<orderFeatureState>(orderFeatureKey);
export const selectListOfOrders= createSelector(
orderState,
({ list}) => list
);

export const selectOrderById = createSelector(
orderState,
(list: any, id: string) => list.find((x: any) => x.id === id)
);

Up to now, we talked about the core features of NGRX, now it’s time to examine an image provided by the official website of NGRX.

It’s clear as a day, that this image depicts the flow of NGRX.

  • When it comes to working with APIs, Databases, or in general asynchronous operations you need to use Effects
  • If you decided to update the store you have to use Reducers
  • When you want to notify your store about a specific event or issue a command for doing something like fetching data you need to dispatch an action from a component
  • If you want to grab a portion of the store you need to use selectors

Conclusion

NgRx is a powerful library for managing state in Angular applications. It provides a way to centralize state management in a predictable and testable way, using a unidirectional data flow. NgRx also provides additional features like effects and selectors, which can help you manage complex states and handle side effects. By using NgRx, you can simplify the logic of your components and improve the performance of your application. If you are working on a large-scale Angular application, using NgRx or a state management library in your project is a must, cheers.

If you want to know how you can implement NGRX in your project check out my article, https://medium.com/mobiroller-tech/implementing-ngrx-in-angular-a-comprehensive-guide-5e8497ed667

--

--