Ela você vai duas soluções!
1. Modifique ChangeDetectionStrategy para OnPush
Para esta solução, você está basicamente dizendo angular:
Pare de verificar se há alterações; farei isso apenas quando eu souber que é necessário
A solução rápida:
Modifique seu componente para que ele use ChangeDetectionStrategy.OnPush
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChildComponent implements OnInit {
// ...
}
Com isso, as coisas parecem não funcionar mais. Isso porque a partir de agora você terá que fazer a chamada Angular detectChanges()
manualmente.
this.cdr.detectChanges();
Aqui está um link que me ajudou a entender o ChangeDetectionStrategy corretamente:
https://alligator.io/angular/change-detection-strategy/
2. Entendendo ExpressionChangedAfterItHasBeenCheckedError
Aqui está um pequeno extrato da resposta tomonari_t sobre as causas desse erro. Tentei incluir apenas as partes que me ajudaram a entender isso.
O artigo completo mostra exemplos de códigos reais sobre todos os pontos mostrados aqui.
A causa raiz é o ciclo de vida angular:
Após cada operação, o Angular lembra quais valores foram usados para executar uma operação. Eles são armazenados na propriedade oldValues da visualização do componente.
Após a verificação de todos os componentes, o Angular inicia o próximo ciclo de resumo, mas em vez de executar operações, ele compara os valores atuais com os que se lembra do ciclo de resumo anterior.
As seguintes operações estão sendo verificadas nos ciclos de resumo:
verifique se os valores passados para os componentes filhos são iguais aos valores que seriam usados para atualizar as propriedades desses componentes agora.
verifique se os valores usados para atualizar os elementos DOM são os mesmos que os valores que seriam usados para atualizar esses elementos agora executam o mesmo.
verifica todos os componentes filhos
E assim, o erro é gerado quando os valores comparados são diferentes. , o blogueiro Max Koretskyi afirmou:
O culpado é sempre o componente filho ou uma diretiva.
E, finalmente, aqui estão algumas amostras do mundo real que geralmente causam esse erro:
- Serviços compartilhados
- Transmissão síncrona de eventos
- Instanciação dinâmica de componentes
Cada amostra pode ser encontrada aqui (plunkr); no meu caso, o problema era uma instanciação de componente dinâmico.
Além disso, pela minha própria experiência, recomendo fortemente que todos evitem a setTimeout
solução, no meu caso causou um loop infinito "quase" (21 chamadas que não estou disposto a mostrar como provocá-las),
Eu recomendaria ter sempre em mente os ciclos de vida angulares para que você possa levar em consideração como eles seriam afetados toda vez que você modificar o valor de outro componente. Com este erro, a Angular está lhe dizendo:
Talvez você esteja fazendo isso da maneira errada, tem certeza de que está certo?
O mesmo blog também diz:
Freqüentemente, a correção é usar o gancho de detecção de alterações correto para criar um componente dinâmico
Um pequeno guia para mim é considerar pelo menos as duas coisas a seguir durante a codificação ( tentarei complementá-lo com o tempo ):
- Evite modificar os valores dos componentes pai dos componentes da criança: em vez disso, modifique-os a partir do pai.
- Quando você usa
@Input
e @Output
directivas tentar evitar desencadear mudanças lyfecycle a menos que o componente é completamente inicializado.
- Evite chamadas desnecessárias,
this.cdr.detectChanges();
pois elas podem acionar mais erros, especialmente quando você está lidando com muitos dados dinâmicos
- Quando o uso de
this.cdr.detectChanges();
for obrigatório, verifique se as variáveis ( @Input, @Output, etc
) usadas estão preenchidas / inicializadas no gancho de detecção direito ( OnInit, OnChanges, AfterView, etc
)
- Quando possível, remova em vez de ocultar , isso está relacionado aos pontos 3 e 4.
Além disso
Se você deseja entender completamente o Angular Life Hook, recomendo que você leia a documentação oficial aqui: