Iniciando estudos de RxJs em Angular
Published: 2022-10-20 17:33:03

## 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](https://www.instagram.com/p/Ci8th7ROUcP/) 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>`

```js
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}`)
  }
}
```

**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`

```js
@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)
    })
  }
}
```

**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:

```js
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'),
};
```

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
```js
  isLoading$: BehaviorSubject<boolean> = new BehaviorSubject(true);
```

- Ao completar a requisição, atualizamos o valor para false

```js
  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);
      }
    })
  }
```

**Passando para o filho**

```html
<child-component
  [name]="user.name"
  [isLoading$]="isLoading$"
>
</child-component>
```

**Recebendo no filho**

```js
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) { }
}
```

**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

```html
<div *ngIf="isLoading$ | async">
  <p>carregando</p>
</div>
```

> 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](https://angular.io/api/common/AsyncPipe).

_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!