[Angular][pt] Desinscrições no Angular: Quando e por quê usar?
Published: 2024-07-05 14:10:41


## Introdução
Nos meus 6 anos trabalhando com Angular, uma pergunta recorrente que vejo aparecer, mesmo de devs com menos experiência, é: "Eu preciso me desinscrever aqui?"

A resposta é: sim, na maioria dos casos. Mas nem sempre é tão simples assim. Neste artigo, quero entender quando e como usar as desinscrições no Angular.

## O que é desinscrição e por que é importante?
Em resumo, desinscrever-se de um observable significa parar de receber notificações dele. Isso é crucial para evitar vazamentos de memória e garantir que seu aplicativo Angular funcione de forma eficiente.

Imagine que você se inscreve para receber uma revista semanal com ofertas de um supermercado local. Essa revista é muito útil enquanto você mora perto do mercado, pois te mantém atualizado com as melhores promoções. Porém, se você se muda para outra cidade onde esse mercado não existe, continuar recebendo essa revista se torna desnecessário e só lota sua caixa de correio com conteúdo que você não vai usar. Nesse caso, é melhor cancelar a inscrição para evitar receber informações irrelevantes.

No Angular, os observables funcionam de maneira semelhante. Quando você se inscreve em um observable, você está basicamente pedindo para receber notificações sempre que algo novo acontecer. Se você não precisa mais dessas notificações, é importante se desinscrever para evitar que o observable continue enviando notificações desnecessárias, o que pode levar a vazamentos de memória.

## Quando me desinscrever?
- **Sempre que você não precisar mais das notificações do observable.** Por exemplo, se você está buscando dados para uma tela e, em seguida, navega para outra tela, não precisa mais das notificações do observable da tela anterior.
- **Quando o componente que está criando a inscrição for destruído.** Isso geralmente acontece automaticamente quando você navega para outra tela, mas é importante verificar se há casos em que isso não acontece e, se necessário, desinscrever-se manualmente no `ngOnDestroy` do componente.

## Como me desinscrever?
Existem diversas maneiras de se desinscrever de um observable no Angular. Aqui estão alguns dos métodos mais comuns:

### 1. Usando o método `unsubscribe()`
Esse é o método mais básico e direto. Você pode armazenar a referência à inscrição em uma variável e chamá-la quando não precisar mais das notificações.

```typescript
const subscription = myObservable.subscribe(data => {
  console.log(data);
});

// ... algum tempo depois ...

subscription.unsubscribe();
```

### 2. Usando o operador `takeUntil()`
Esse operador permite que você se desinscreva de um observable quando outro observable for concluído. Isso é útil em situações em que você deseja se desinscrever de um observable principal quando um observable secundário for concluído.

```typescript
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

const subject = new Subject();

const subscription = myObservable.pipe(
  takeUntil(subject)
).subscribe(data => {
  console.log(data);
});

// ... algum tempo depois ...

subject.next();
```

### 3. Usando bibliotecas de terceiros
Existem diversas bibliotecas de terceiros que podem te ajudar a gerenciar desinscrições de forma mais fácil. Uma biblioteca popular é o `ngx-unsubscribe`.

## Desinscrição automática com bibliotecas nativas do Angular
Algumas bibliotecas nativas do Angular já fazem a desinscrição automaticamente. É o caso do `HttpClientModule` e do `Router`. Isso significa que você não precisa se preocupar em se desinscrever das solicitações HTTP ou das alterações de rota.

### HttpClientModule
O `HttpClientModule` desinscreve automaticamente das solicitações HTTP quando a requisição é concluída ou quando o componente que fez a requisição é destruído.

### Router
O `Router` desinscreve automaticamente das alterações de rota quando a navegação é concluída ou quando o componente que está escutando as alterações de rota é destruído.

### O async Pipe
O `async` pipe é uma maneira conveniente de lidar com observables no template do Angular. Ele automaticamente se inscreve no observable e se desinscreve quando o componente é destruído. Isso ajuda a evitar vazamentos de memória sem precisar escrever código de desinscrição manual.

#### Exemplo de uso do `async` pipe:

```html
<div *ngIf="authService.isLoggedIn$ | async as isLoggedIn">
  <p *ngIf="isLoggedIn">Você está logado!</p>
  <p *ngIf="!isLoggedIn">Você não está logado.</p>
</div>
```

Neste exemplo, `isLoggedIn$` é um observable exposto pelo serviço `AuthService`. O `async` pipe se inscreve nesse observable e atualiza automaticamente o template com base no seu valor atual.

## E os observables do Reactive Forms?
No caso dos observables do Reactive Forms, a desinscrição geralmente não é necessária. Isso porque esses observables são gerenciados internamente pelo Angular e são desinscritos automaticamente quando o componente é destruído.

## Exemplo Prático: Usando `valueChanges` e Desinscrição em um Componente de Login

Vamos ver um exemplo prático de como usar a desinscrição em um componente de login simples. No nosso exemplo, vamos usar o operador `takeUntil` para nos desinscrever quando o componente for destruído e também monitorar as mudanças de valor dos campos de entrada.

```typescript
import { Component, OnInit, OnDestroy } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';
import { AuthService } from '../auth.service';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { Router } from '@angular/router';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit, OnDestroy {
  loginForm: FormGroup;
  private unsubscribeSubject = new Subject<void>();

  constructor(private authService: AuthService, private router: Router) { }

  ngOnInit(): void {
    this.loginForm = new FormGroup({
      email: new FormControl('', [Validators.required, Validators.email]),
      password: new FormControl('', [Validators.required])
    });

    // Monitorar mudanças de valor usando valueChanges
    this.loginForm.valueChanges
      .pipe(takeUntil(this.unsubscribeSubject))
      .subscribe(changes => {
        console.log('Form value changed:', changes);
      });
  }

  ngOnDestroy(): void {
    this.unsubscribeSubject.next();
    this.unsubscribeSubject.complete();
  }

  onSubmit(): void {
    const { email, password } = this.loginForm.value;

    this.authService.login(email, password)
      .pipe(
        takeUntil(this.unsubscribeSubject) // Desinscreve quando o unsubscribeSubject for emitido
      )
      .subscribe(
        () => {
          // Login efetuado com sucesso
          this.router.navigate(['/']);
        },
        (error) => {
          // Erro no login
          console.error(error);
        }
      );
  }
}
```

Neste exemplo, além de usar o operador `takeUntil` para desinscrever-se do observable de login quando o componente for destruído, também monitoramos as mudanças de valor do formulário usando `valueChanges`. Isso garante que as mudanças de valor sejam registradas enquanto o componente está ativo e paradas quando o componente é destruído.

## Resumo
Neste artigo, vimos que as desinscrições são cruciais para evitar vazamentos de memória e garantir que seu aplicativo Angular funcione de forma eficiente. Abordamos os seguintes tópicos:

1. **O que é desinscrição e por que é importante?**
2. **Quando me desinscrever?**
3. **Como me desinscrever?**
4. **Desinscrição automática com bibliotecas nativas do Angular**
5. **O `async` Pipe**
6. **E os observables do Reactive Forms?**
7. **Exemplo prático: Usando `valueChanges` e Desinscrição em um Componente de Login**

Espero que este artigo tenha te ajudado a entender melhor o conceito de desinscrições no Angular e como aplicá-lo em seus projetos.

### Dicas Extras:

- Sempre que você criar uma inscrição em um observable, pense em como você vai se desinscrever dela.
- Utilize ferramentas como o Angular DevTools para inspecionar as inscrições em seus componentes e identificar possíveis vazamentos de memória.
- Adote bibliotecas de terceiros como o `ngx-unsubscribe` para facilitar o gerenciamento de desinscrições em seus projetos.

Lembre-se: desinscrever-se é uma prática essencial para o desenvolvimento de aplicativos Angular robustos e eficientes.