ExpressionChangedAfterItHasBeenCheckedError en Angular: ¿qué, por qué y cómo solucionarlo?

ExpressionChangedAfterItHasBeenCheckedError es sin duda mi error favorito en aplicaciones angulares.

Encontré mucho este error cuando comencé a trabajar con Angular. Según GitHub, también lo hacen muchos otros.

¿Cuándo se lanzará ExpressionChangedAfterItHasBeenCheckedError?

Las razones más comunes son:

  1. Está ejecutando código en AfterViewInit, que a menudo ocurre cuando se trabaja con ViewChild, ya que no está definido hasta que se llama a AfterViewInit.
  2. Estás manipulando el DOM directamente (por ejemplo, usando jQuery). Angular no siempre puede detectar estos cambios y reaccionar adecuadamente.
  3. También puede ocurrir debido a las condiciones de carrera cuando está llamando a funciones dentro de su plantilla HTML.

¿De qué trata ExpressionChangedAfterItHasBeenCheckedError al intentar advertirme?

ExpressionChangedAfterItHasBeenCheckedError se produce cuando una expresión en su HTML ha cambiado después de que Angular lo haya verificado (es un error muy expresivo).

Este error solo se produce en modo de desarrollo y por una buena razón; a menudo es una señal de que debe refactorizar su código, ya que Angular le advierte que este cambio en su expresión no se detectará al habilitar el modo de producción.

Una de las razones por las que el modo de producción es más rápido que el modo de desarrollo es que Angular omite algunas comprobaciones (por ejemplo, detección de cambios después de AfterViewInit) que se realizan en modo de desarrollo. Eso significa que el código que funcionará bien en modo de desarrollo no funcionará en modo de producción.

Aquí hay un ejemplo que funcionaría bien en modo desarrollo pero no en modo producción:

Cómo arreglar ExpressionChangedAfterItHasBeenCheckedError

Arreglar uno

Como solución rápida, setTimeout o ChangeDetectorRef se utilizan a menudo para hacer que el error desaparezca.

Esto último es mejor, ya que con ChangeDetectorRef se verifica la vista del componente y sus elementos secundarios. Por otro lado, setTimeout hará que Angular verifique toda la aplicación en busca de cambios, lo cual es mucho más costoso.

Arreglar dos

A veces, el error es aún más fácil de solucionar: simplemente mueva su código a OnInit.

A menos que tenga que confiar en ViewChild, o si algún código solo se ejecuta después de que Angular haya inicializado completamente la vista de un componente, pasar a OnInit resolverá su problema.

Esto se debe a que Angular realizará la detección de cambios después de OnInit tanto en el modo de producción como en el de desarrollo.

Arreglar tres

¿No te gusta la magia angular y cómo detecta los cambios? Simplemente desactive la detección automática de cambios en su componente y dígale a Angular cuándo debe detectar los cambios.

ChangeDetectionStrategy se puede especificar en un decorador de componentes para OnPush. Ahora, Angular solo detectará los cambios de entrada automáticamente, y el resto depende de usted.

Si bien hay menos magia involucrada al habilitar la estrategia OnPush, también obtienes un rendimiento mejorado ya que Angular tiene menos trabajo que hacer. Esto puede ser útil para optimizar componentes grandes y complejos.

Por otro lado, debe asegurarse de dejar que Angular recoja los cambios. Si no lo hace, generalmente verá errores de UI (por ejemplo, un modal no desaparece).

Por lo tanto, no aplique esto con demasiada entusiasmo sin verificar a fondo su componente.

Conclusión

Ahora debería poder entender cuándo y por qué ocurre el infame ExpressionChangedAfterItHasBeenCheckedError.

Como puede ver, hay varias formas de lidiar con este error. Solo asegúrese de que realmente está resolviendo el problema subyacente real, en lugar de solucionarlo.