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