A Verdadeira Utilidade do ngOnDestroy no Angular

07/08/2025


No universo do desenvolvimento com Angular, o ngOnDestroy é uma das propriedades mais cruciais do ciclo de vida de um componente. No entanto, sua função é frequentemente mal interpretada, levando a problemas de desempenho e, mais comumente, a vazamentos de memória (memory leaks).

Este artigo visa esclarecer a utilidade real de ngOnDestroy, demonstrando por que ele é indispensável para a saúde e a estabilidade de suas aplicações.

O Que é ngOnDestroy?

ngOnDestroy é uma interface do Angular que, quando implementada, fornece um método de gancho de ciclo de vida. O Angular executa este método imediatamente antes que um componente, diretiva ou pipe seja destruído. O termo "destruído" significa que ele está sendo removido da árvore de componentes e do DOM, o que geralmente acontece durante a navegação entre rotas, o uso de *ngIf que se torna false, ou a remoção manual por meio de APIs do Angular.

A principal função de ngOnDestroy não é remover o elemento HTML (o Angular já faz isso automaticamente), mas sim ser o local onde você pode e deve realizar a limpeza de recursos.

Por Que a Limpeza é Tão Importante?

Quando um componente é removido, todas as suas assinaturas de observables, listeners de eventos, timers (setTimeout, setInterval) e outras referências continuam a existir na memória se não forem explicitamente canceladas. Isso significa que mesmo que o componente não esteja mais visível na tela, ele ainda está "vivo" na memória, consumindo recursos e potencialmente executando lógica em segundo plano.

Esse fenômeno é o que conhecemos como vazamento de memória. Com o tempo, um acúmulo desses vazamentos pode degradar o desempenho da aplicação, tornando-a lenta e até mesmo levando a falhas. O ngOnDestroy é o nosso ponto de controle para evitar isso.

Casos de Uso Comuns e Exemplos Práticos

A seguir, estão os cenários mais comuns onde a utilização correta de ngOnDestroy é vital.

1. Cancelando Assinaturas de Observables

Este é o caso de uso mais frequente. As requisições HTTP e outras fontes de dados que retornam um Observable precisam ser canceladas. Uma forma popular e robusta de fazer isso é usando a combinação de Subject e takeUntil.

import { Component, OnInit, OnDestroy } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

@Component({
  selector: 'app-user-profile',
  template: `<p>Dados do Usuário</p>`
})
export class UserProfileComponent implements OnInit, OnDestroy {
  // O Subject será nosso gatilho para a desinscrição
  private destroy$: Subject<boolean> = new Subject<boolean>();
  userData: any;

  constructor(private http: HttpClient) { }

  ngOnInit() {
    // Chamada HTTP para buscar dados
    this.http.get('https://api.example.com/users/1')
      .pipe(
        // O takeUntil garante que a assinatura será cancelada quando destroy$ emitir um valor
        takeUntil(this.destroy$)
      )
      .subscribe(data => {
        this.userData = data;
      });
  }

  ngOnDestroy() {
    // Emite um valor para o Subject para desinscrever todas as assinaturas
    this.destroy$.next(true);
    // Completa o Subject
    this.destroy$.complete();
  }
}

2. Removendo Listeners de Eventos do DOM

Se você adicionar um listener de evento a um elemento global (window, document) ou a um elemento nativo de forma manual, ele não será removido automaticamente.

import { Component, OnDestroy, OnInit } from '@angular/core';

@Component({
  selector: 'app-scroll-listener',
  template: `<p>Scroll para ativar algo</p>`
})
export class ScrollListenerComponent implements OnDestroy, OnInit {

  constructor() { }

  ngOnInit() {
    // Adiciona um listener de evento ao objeto 'window'
    window.addEventListener('scroll', this.onScroll, true);
  }

  => {
    console.log('Componente está rolando!');
    // Lógica de manipulação de evento...
  }

  ngOnDestroy() {
    // É crucial remover o listener para evitar vazamentos de memória
    window.removeEventListener('scroll', this.onScroll, true);
  }
}

3. Limpando Timers

setInterval e setTimeout também precisam ser cancelados para que a lógica pare de ser executada depois que o componente é removido.

import { Component, OnInit, OnDestroy } from '@angular/core';

@Component({
  selector: 'app-timer',
  template: `<p>Contagem regressiva: {{ counter }}</p>`
})
export class TimerComponent implements OnInit, OnDestroy {
  counter = 10;
  timerId: any;

  ngOnInit() {
    this.timerId = setInterval(() => {
      this.counter--;
      if (this.counter === 0) {
        clearInterval(this.timerId);
      }
    }, 1000);
  }

  ngOnDestroy() {
    // Limpa o timer para que ele pare de ser executado
    if (this.timerId) {
      clearInterval(this.timerId);
    }
  }
}

Em uma aplicação Angular, o ngOnDestroy é um dos métodos do ciclo de vida de um componente, projetado para ser chamado automaticamente pelo framework quando o componente está prestes a ser destruído. Sua função principal é liberar recursos — cancelar assinaturas de observables, limpar timers ou remover event listeners criados manualmente — garantindo que o componente não deixe resíduos na memória após sua remoção.

No entanto, um erro comum é utilizá-lo para remover manualmente o elemento do DOM, por exemplo:

typescript
CopiarEditar
ngOnDestroy() {
  this.elementRef.nativeElement.remove();
}

Esse uso é incorreto e traz uma série de problemas:

  1. Vazamentos de memória
  2. Ao manipular o DOM diretamente e forçar a remoção do elemento, o Angular perde o controle do processo de limpeza interna. Isso significa que assinaturas, timers e listeners ainda podem continuar ativos em segundo plano, causando vazamentos de memória e comprometendo o desempenho da aplicação.
  3. Conflito com o mecanismo do Angular
  4. O Angular já possui um fluxo definido para criar e destruir componentes. Ao interferir manualmente, você quebra esse ciclo natural, o que pode gerar comportamentos imprevisíveis, erros em tempo de execução e dificultar a depuração.
  5. Código redundante e propenso a erros
  6. A remoção manual do elemento é desnecessária, pois o Angular já realiza essa ação de forma otimizada. Incluir código redundante apenas aumenta a complexidade e o risco de bugs.

Portanto, o ngOnDestroy deve ser usado exclusivamente para liberar recursos alocados pelo próprio componente, não para manipular ou remover elementos do DOM. Respeitar esse papel mantém o código limpo, previsível e alinhado às boas práticas do framework.



O ngOnDestroy é um dos pilares da arquitetura Angular para garantir que as aplicações sejam performáticas e livres de vazamentos de memória. Sua verdadeira utilidade reside na limpeza de recursos alocados pelo componente, e não na remoção do elemento HTML. Ao adotar a prática de cancelar todas as assinaturas, timers e listeners de eventos em ngOnDestroy, você garante que sua aplicação rodará de forma eficiente e confiável, mesmo em cenários de alta complexidade.