Make NgRx hold Business Logic: Dumb components, Smart store

Make NgRx hold Business Logic: Dumb components, Smart store

State management is now essential for front-end apps. It came from React community with Redux. With Angular, you can also use Redux for state management but NgRx is considered as the go-to for Angular.

State management is now essential for front-end apps. It came from React community with Redux. With Angular, you can also use Redux for state management but NgRx is considered as the go-to for Angular.

NgRx Store provides reactive state management for Angular apps inspired by Redux — NgRx website

Six months ago, our team made the choice to “move everything” into NgRx. It means at least every HTTP call response must be in the store. This isn't recommended but we did it anyway.

After developing new features all in NgRx, the whole team still 100% agree with this choice. In this article, you won’t learn what is state management or how NgRx works. This is focused on why we moved all our business logic to NgRx and why you should consider it.

A brand new project#

Our team started a new project using Angular, a reporting app called Instant Insights. It displays a bunch of data through plots and tables. The user can apply many filters on the whole page such as fields to show and report period.

Every single component needs to access to those filters. A common issue with component data sharing is** prop drilling**.

@Component({
  selector: 'my-dashboard',
  template: `<my-graph [filters]="filters"></my-graph>`
})
export class DashboardComponent {  
  // Don't need filter but necessary to pass it to my-graph
  // It's called prop drilling
  @Input() filters;  
}
<>

Another issue is the complexity of components interactions. There is a lot of @Input and @Output whose purpose is to trigger other components reload. It makes the code hard to digest since our app contains a lot of filters.

@Component({
  selector: 'app-root',
  template: `
    <app-sort
      [defaultSort]="currentSort"
      (sortChange)="updateData($event)">
    </app-sort>

    <app-data [sort]="currentSort"></app-data>
  `,
})
export class AppComponent {
  // Sort filter is stored here in the end
  currentSort = 'Price';

  updateData($event) {
    this.currentSort = $event;
  }
}

@Component({
  selector: 'app-sort',
  template: `
    <input 
      *ngFor="let sort of sorts"
      type="radio"
      name="sort" 
      [value]="sort"
      [checked]="sort === defaultSort"
      (change)="sortClick($event)"/>{{ sort }}
  `,
})
export class SortComponent {
  @Input() defaultSort;
  @Output() sortChange = new EventEmitter();

  sorts = ['Price', 'Size'];

  sortClick($event) {
    const sort = $event.target.value;
    this.sortChange.emit(sort);
  }
}

@Component({
  selector: 'app-data',
  template: `<div>Data sorted by {{ sort }}</div>`,
})
export class DataComponent {
  @Input() sort;
}
<>

In this configuration, the top AppComponent hold the filters values. It's also responsible for listening changes through @Output and update other components thanks to @Input.

A common method to simplify interactions consists of using singleton services that hold shared data. The code is less verbose but almost prevent you from using OnPush strategy. Check this Stackblitz to see how it looks with services.

Using NgRx to handle filters and trigger some components reload was our solution. This way, the filters are held in the store. Any component can get the store instance using dependency injection to retrieve the filters. You can consult the store content and history with the Redux DevTool extension..

This solution doesn't come without drawbacks. It made our component less reusable since there are no more inputs and outputs, all data are in the store.

Redux DevTool extension

With this architecture, both components and the store hold the business logic. To access data from the store, a component needs to subscribe to it (and also unsubscribe). In templates, the async pipe does the job for you. Yet, when you need to access store data from component methods it can’t help.

ngrx angular

Bootstrap 5 Complete Course with Examples

Bootstrap 5 Tutorial - Bootstrap 5 Crash Course for Beginners

Nest.JS Tutorial for Beginners

Hello Vue 3: A First Look at Vue 3 and the Composition API

Building a simple Applications with Vue 3

Deno Crash Course: Explore Deno and Create a full REST API with Deno

How to Build a Real-time Chat App with Deno and WebSockets

Convert HTML to Markdown Online

HTML entity encoder decoder Online

Angular NgRx Store | Angular 9 NgRx Example

Angular NgRx Store is a client-side data management pattern used in large applications. The Ngrx/Store implements the Redux pattern using RxJS observables.

Install Angular - Angular Environment Setup Process

Install Angular in easy step by step process. Firstly Install Node.js & npm, then Install Angular CLI, Create workspace and Deploy your App.

Basics of Angular: Part-1

What is Angular? What it does? How we implement it in a project? So, here are some basics of angular to let you learn more about angular. Angular is a Typesc

How to Add Swiping to an Angular App with NgRx

NgRx, is an Angular library that is used for reactive state management for Angular app. NgRx implements the pattern of Redux with the use of the popular Angular 2 RxJs observable. It provides several advantages for *Angular development* via simplifying the app state into plain objects and enforcement of unidirectional data flow among others. By triggering side effects, the Effects library enables an app to communicate with the outside world.

Angular 10 NgRX Store by Example

In this tutorial we’ll learn how to use the NgRX store in our Angular 10 example application. We’ll see how we can create actions, reducers, and dispatch actions. The Angular NgRx store is a client-side data management pattern that implements the Redux pattern, and which was invented by Facebook using RxJS observables. As a prerequisite, you need to have Node.js and Angular CLI installed on your local development machine for this to work.