DEV Community

Cover image for Iniciando estudos de RxJs em Angular
Fernanda Kipper
Fernanda Kipper

Posted on

Iniciando estudos de RxJs em Angular

O que é RxJs?

RxJs é uma biblioteca que fornece formas de trabalhar com programação assíncrona e baseada em eventos - reativa - usando observables. A biblioteca provém um tipo principal o Observable, tipos satélites como Subjects, Observers e Schedulers e também operadores para lidar a coleção de eventos assíncronos.

Recapitulando: o que são Observables?

O Observable é a peça chave do Design Pattern Observer, baseado em eventos o padrão define Observable como o objeto de interesse e que pode ser observado, o mesmo guarda uma lista de interessados em suas mudanças - Observers ou Subscribers - e emite um evento avisando aos interessados todas as vezes que ocorrer uma mudança em seus itens.
Se ainda não ficou claro, recomendo a leitura do meu post sobre o Padrão Observer antes de continuar.

RxJs + Angular

O novo Angular foi construído em cima da programação reativa, o uso de Promises foi abandonado e fora adotado o uso de Observables, e ai que entra o RxJs.

Requisições HTTP

Vamos começar com o básico, lidando com respostas de requisições HTTP. Normalmente, fariamos usando Promises como acontece em React JS, porém em Angular vamos usar Observables do RxJS.

Criando nosso service
Ele que realiza a requisição e retorna um Observable do tipo HttpResponse<User>

import { Injectable } from "@angular/core";
import { HttpClient, HttpResponse } from '@angular/common/http';
import { Observable } from 'rxjs';


export interface IUser {
  name: string;
  id: string;
  imgUrl?: string;
}

@Injectable({
  providedIn: 'root'
})
export class UserService {
  constructor(private httpClient: HttpClient) {}

  getUser(id: string):  Observable<HttpResponse<IUser>> {
    return this.httpClient.get<HttpResponse<IUser>>(`/api/users/${id}`)
  }
}
Enter fullscreen mode Exit fullscreen mode

Consumindo

Nosso componente irá chamar o UserService, e para receber a resposta da requisição precisamos realizar o subscribe no Observable retornado pelo método getUser(), passando como parâmetro para o método subscribe um objeto do tipo observer

@Component({
  selector: 'app-user',
  templateUrl: './user.component.html',
  styleUrls: ['./user.component.scss']
})
export class UserComponent implements OnInit {
  private user!: IUser;

  constructor(private userService: UserService) { }

  ngOnInit(): void {
    this.getUserData();
  }

  getUserData(){
    this.userService.getUser('1234').subscribe({
      next: (data) => {
        if(data.body) this.user = data.body
      },
      error: (err) => console.log(err)
    })
  }
}
Enter fullscreen mode Exit fullscreen mode

Observer
O Observer é o consumidor dos valores emitidos pelo o Observable, ele nada mais é que um objeto que possui callbacks para cada evento do emissor. Exemplo:

const observer = {
  next: x => console.log('Observer recebeu o prox valor: ' + x),
  error: err => console.error('Observer recebeu um erro: ' + err),
  complete: () => console.log('Observer completou o recibimento'),
};
Enter fullscreen mode Exit fullscreen mode

Dentro de cada um desses callbacks podemos realizar o necessário com o dado emitido.

Eventos Pai -> Filho

O segundo caso que irei demostrar é quando precisamos que um componente filho reaja a um evento do seu pai.

Exemplo: enquanto a requisição para buscar o usuário não finaliza, quero que um componente filho mostre a mensagem "carregando" e quando finalizar ele mostra os dados normalmente.

Entendo o conceito de Subject

Enquanto Observables são unicast, ou seja, cada subscriber possui uma execução única e indepente (seu próprio "canal") do Observable pois cada subscribe() invoca uma nova execução. Os Subjects são multicast, eles não invocam uma nova execução para cada subscribe(), eles simplemente adicionam na lista de Observers e avisa a todos pelo mesmo "canal" quando houver uma mudança.

Criando um Behavior Subject
Para emitir eventos do pai para o filho, vamos utilizar Behavior Subject, que consiste em um Subject que possui valor inicial e emite seu valor atual para cada Observer inscrito.

  • Criamos um atributo isLoading$ no componente pai
  isLoading$: BehaviorSubject<boolean> = new BehaviorSubject(true);
Enter fullscreen mode Exit fullscreen mode
  • Ao completar a requisição, atualizamos o valor para false
  getUserData(){
    this.userService.getUser('1234').subscribe({
      next: (data) => {
        if(data.body) this.user = data.body
      },
      error: (err) => console.log(err),
      complete: () => {
        this.isLoading$.next(false);
      }
    })
  }
Enter fullscreen mode Exit fullscreen mode

Passando para o filho

<child-component
  [name]="user.name"
  [isLoading$]="isLoading$"
>
</child-component>
Enter fullscreen mode Exit fullscreen mode

Recebendo no filho

import { Component, OnInit } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { UserService, IUser } from 'src/app/shared/services/user.service';

@Component({
  selector: 'child-component',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.scss']
})
export class ChildComponent implements OnInit {
  @Input() name?: string;
  @Input() isLoading$: BehaviorSubject<boolean>;

  constructor(private userService: UserService) { }
}
Enter fullscreen mode Exit fullscreen mode

Utilizando o Behavior Subject
Agora no template do componente filho vamos usar um condicional para saber quando mostrar "carregando".

Quando o valor atual for true => ele deve mostrar
Quando o valor atual for false => ele deve esconder a div

<div *ngIf="isLoading$ | async">
  <p>carregando</p>
</div>
Enter fullscreen mode Exit fullscreen mode

Note que utilizei o pipe async, um recurso fornecido pelo Angular, que automaticamente realiza o subscribe no Observable - nesse caso é nosso Behavior Subject isLoading$ - e retorna sempre o último valor emitido. Se quiser saber mais sobre esse operador, recomendo a leitura da documentação do Angular.

Para usar o pipe async não esqueca de importar o CommonModule no módulo do seu componente.


Quando iniciei meus estudos em Angular, dois anos atrás, RxJs era um assunto bem conturbado para mim e existiam poucos conteúdos em português, mesmo ele sendo uma peça fundamental para construirmos aplicações mais robustas com Angular.
Então, resolvi compartilhar um pouco do que aprendi nesses anos para ajudar quem esteja começando agora, espero que você tenha gostado do artigo 😊

Seu feedback é bem vindo!

Top comments (0)