Avoiding multiple API calls in Angular by using shareReplay method of RxJS

While working with some Angular projects, we've to subscribe the same api in to different methods in a component. In order to avoid that we can use shareReplay method of RxJS.

Lets consider an app which has two buttons and two different methods gets called on clicking on those buttons. But, internally the two methods will subscribe the same api two times. Suppose user clicks the button multiple times, then we've to call the same api multiple times to display the number of completed/incomplete tasks.




On clicking the `Completed Todos` and `Incomplete Todos` buttons, same API got two times. This will increase the load on server and increase the loading time of UI. Henceforth, reduces the performance of our application.

We can avoid calling multiple API services with the help of shareReplay method of RxJS. shareReplay  subscribes the observable, caches the response and multicasts it to all the subscribers without calling the API multiple times.

Lets see the above example with shareReplay. The only thing we've to do is include `shareReplay` method in the API call.












Now, if we clicked on both buttons, it'll be called only once nevertheless of how many times you click the buttons only one time it gets called.


Here is the whole structure of the project

app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';

import { AppComponent } from './app.component';
import { HelloComponent } from './hello.component';
import { HttpClientModule } from '@angular/common/http';
import { RouterModule } from '@angular/router';

@NgModule({
  imports: [BrowserModuleFormsModuleHttpClientModuleRouterModule],
  exports: [RouterModule],
  declarations: [AppComponentHelloComponent],
  bootstrap: [AppComponent],
})
export class AppModule {}

app.component.ts:

import { HttpClient } from '@angular/common/http';
import { Component } from '@angular/core';
import { todosService } from './app.service';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  completedTodosnumber = 0;
  incompleteTodosnumber = 0;
  todoResponseany;
  constructor(private todoServicetodosServiceprivate httpHttpClient) {}
  ngOnInit() {
    this.todoResponse = this.todoService.getTodosList();
  }
  getIncompleteTods() {
    this.incompleteTodos = 0;
    //Avoid this
    // this.todoService.getTodosList().subscribe((res: Array<any>) => console.log(res));
    this.todoResponse.subscribe((resArray<any>) => {
      res.forEach((todo=> {
        if (!todo.completed) {
          this.incompleteTodos++;
        }
      });
    });
  }
  getCompletedTodos() {
    this.completedTodos = 0;
    //Avoid this
    // this.todoService.getTodosList().subscribe((res: Array<any>) => console.log(res));
    this.todoResponse.subscribe((resArray<any>) => {
      res.forEach((todo=> {
        if (todo.completed) {
          this.completedTodos++;
        }
      });
    });
  }
}

app.component.html

<button (click)="getCompletedTodos()">Completed todos</button>
<p *ngIf="completedTodos > 0">Completed todos are : {{ completedTodos }}</p>
<br /><br />

<button (click)="getIncompleteTods()">Incomplete todos</button>
<p *ngIf="incompleteTodos > 0">Incomplete todos are : {{ incompleteTodos }}</p>

app.service.ts

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { shareReplay } from 'rxjs/operators';

@Injectable({
  providedIn: 'root',
})
export class todosService {
  constructor(private httpHttpClient) {}
  getTodosList() {
    let url = 'https://jsonplaceholder.typicode.com/todos/';
    return this.http.get(url).pipe(shareReplay());
  }
}

Link for whole code : Github

Link to check the output : Stackblitz

Comments

Popular posts from this blog

How to improve the unit tests running time in Angular