Inputs e inicialização não são o mesmo evento
ngOnInit executa uma vez depois de Angular inicializar os inputs do componente. Quando ngOnChanges também está implementado, a primeira chamada ocorre antes de ngOnInit. Mudanças posteriores de inputs podem originar novas chamadas ngOnChanges, sem repetir a inicialização única.
SimpleChanges permite consultar valor anterior, valor atual e se é a primeira mudança. Se o input value tem alias publicValue, a chave do registo continua a ser o nome da propriedade TypeScript value. Um alias usado no template não renomeia a API interna de observação.
Destruição e responsabilidade de limpeza
DestroyRef permite registar callbacks com onDestroy perto do local que prepara o recurso. Quando é injetado no âmbito de um componente ou diretiva, a limpeza acompanha a destruição desse proprietário; noutros âmbitos acompanha o injector correspondente.
O valor devolvido por onDestroy é uma função para retirar o registo do callback. Chamá-la não destrói o componente nem executa a limpeza registada. Esta diferença importa quando um recurso termina antes do proprietário: a aplicação pode libertá-lo e retirar um callback que já não deve ser executado, conforme o contrato desse recurso.
Derivar valores antes de criar efeitos
computed expressa um valor calculado a partir de signals. No exemplo, label depende de selected e não precisa de outro signal gravável sincronizado através de effect. Effects são úteis quando leituras reativas devem provocar trabalho imperativo numa API não reativa, como a notificação local apresentada.
O efeito rastreia as leituras efetivamente realizadas na sua execução; não é uma lista automática de todas as propriedades da classe. Duplicar estado derivado introduz mais pontos de escrita e pode criar ciclos ou momentos de incoerência. Primeiro identifica se precisas de um valor ou de uma ação.
Limpar antes da próxima execução
A função passada a effect recebe onCleanup, que regista trabalho a executar antes de o efeito voltar a correr ou ser destruído. No exemplo, cada execução captura o seu id e o seu timer. Uma nova execução cancela o timer anterior ainda pendente, evitando a notificação antiga nesse caso.
O cancelamento não retira mensagens já emitidas. Effects criados no contexto do componente são normalmente destruídos com ele. Se optares por manualCleanup: true, assumes a responsabilidade de conservar o EffectRef e chamar destroy quando o contrato terminar.
Guardar apenas a referência sem a destruir não satisfaz essa responsabilidade.
Subscrições precisam de um âmbito
takeUntilDestroyed associa a conclusão de uma subscrição à destruição do âmbito indicado. Dentro de um contexto de injeção, pode obter DestroyRef implicitamente. Num método acionado por um evento, esse contexto normalmente já não existe: conserva uma referência obtida num initializer e passa-a explicitamente a takeUntilDestroyed.
Isto evita transformar um mecanismo de limpeza num erro de resolução DI. A duração escolhida também interessa: usar um DestroyRef de uma instância mais longa pode manter a subscrição depois do componente consumidor desaparecer. Define o proprietário do recurso antes de escolher a referência.
Trabalho que depende do DOM atualizado
Um effect normal não é uma garantia de execução depois da atualização do DOM. Para uma integração reativa que precisa desse estado, considera afterRenderEffect conforme o contrato documentado. afterNextRender e afterEveryRender registam callbacks após a renderização da aplicação, e devem ser chamados num contexto de injeção.
Estes callbacks não são executados em renderização no servidor ou prerender. Não os uses como único local de uma transformação necessária à resposta do servidor. Distingue cálculo de dados, observação de inputs e acesso a elementos renderizados antes de escolher um hook pelo seu nome.
Respostas tardias e limites do cancelamento
DestroyRef.destroyed permite verificar se o proprietário já terminou antes de aplicar uma atualização tardia. Esta verificação é útil quando um callback assíncrono pode chegar após a destruição, mas não cancela automaticamente a Promise ou a operação remota.
Uma resposta de sucesso HTTP também não prova que a instância local ainda existe. Na revisão de um incidente, regista separadamente início da operação, destruição local, receção do resultado e decisão de o aplicar ou ignorar. Assim, a explicação da limpeza permanece fiel ao que foi interrompido e ao que ainda pode ter produzido efeitos.
// Reading example: synthetic selection notifications; no application bootstrap.
import {Component, computed, effect, signal} from '@angular/core';
@Component({
selector: 'selection-notice', standalone: true,
template: `<p>{{ label() }}</p>
<button type="button" (click)="toggle()">Change selection</button>`,
})
export class SelectionNotice {
readonly selected = signal('A');
readonly label = computed(() => 'Selected: ' + this.selected());
constructor() {
effect(onCleanup => {
const id = this.selected();
const timer = setTimeout(() => console.info('Selection notice:', id), 1000);
onCleanup(() => clearTimeout(timer));
});
}
toggle() { this.selected.update(id => id === 'A' ? 'B' : 'A'); }
}label deriva da seleção sem duplicar estado gravável. O effect cria uma notificação local atrasada para o id que leu; onCleanup cancela esse timer antes da próxima execução ou da destruição. Se o timer já tiver disparado, limpar o identificador não apaga a mensagem emitida.
A ordem relativa de cliques, execução do efeito e timer é uma premissa que deve ser explicitada num cenário.
Armadilhas comuns
Usar ngOnInit para todas as mudanças posteriores; copiar valores derivados através de effects; assumir que um effect normal vê o DOM já atualizado; chamar inject implicitamente num handler; esquecer destroy em manualCleanup; atribuir rollback remoto à limpeza local.
Tópicos relacionados: Signals, inputs e contratos de outputs · Injeção de dependências e ciclo de vida dos serviços · HTTP, streams e aceitação de respostas
Escolhe o mecanismo pelo evento observado: inputs, dependências reativas, renderização ou destruição. Depois identifica a duração do recurso e a ação de limpeza. A limpeza impede trabalho futuro abrangido pelo seu contrato; não elimina efeitos que já ocorreram.
Referência: Input initialization and changes · Angular 22; standalone components