$ status: en construcción · v0.1 — el contenido todavía está creciendo
pulpocode
Vigente · Desarrollo · Devs · 12 min de lectura (aprox.) · actualizado 15 may 2026

Detección de cambios en Angular: de Default a Signals

Tu app empieza bien, pero después de meses se vuelve perezosa. El culpable suele ser invisible: una mala gestión de la detección de cambios. Marco práctico para pasar de Default a OnPush a Signals sin convertirlo en una religión.

Muchos culpan al framework, pero Angular es rápido si sabes cómo guiarlo. En este capítulo no solo entenderás por qué tu app es lenta — vamos a visualizarlo. Una demo donde los componentes parpadean al ser comprobados. Y al final, criterio claro para saber cuándo usar OnPush y cuándo apoyarte en Signals.

Qué es realmente la detección de cambios

Piensa en zone.js como un mayordomo ansioso que, ante cualquier evento (un clic, un setTimeout, una llamada HTTP), corre a revisar cada habitación (componente) de la casa para ver si algo cambió.

Funciona, pero es ineficiente: el mayordomo revisa la habitación de invitados aunque nadie haya entrado.

La tiranía del Default

Montaje de la demo:

  • AppComponent
    • ParentComponent
      • ChildA
      • ChildB

El truco para ver el coste: usamos ngDoCheck para hacer “parpadear” cada componente que Angular comprueba.

@Component({ /* ... */ })
export class ChildA implements DoCheck {
  @HostBinding('style.background') bg = 'white';

  ngDoCheck() {
    this.bg = 'yellow';
    setTimeout(() => (this.bg = 'white'), 200);
  }
}

Resultado: haces clic en un botón en AppComponent (sin pasar datos) y todos los hijos parpadean. Un clic en la raíz, que no tenía nada que ver con ChildB, forzó a Angular a comprobarlo. Multiplica esto por cientos de componentes y ya tienes una app que se siente lenta sin un motivo evidente.

El poder de ChangeDetectionStrategy.OnPush

Al poner OnPush, le decimos al componente:

“No me revises a menos que sea necesario.”

Se actualiza solo si:

  • Sus @Input cambian (referencia nueva, no mutación).
  • Se dispara un evento dentro del componente ((click), etc.).
  • Lo fuerzas manualmente (markForCheck).
  • Un async pipe recibe un nuevo valor.

Misma demo, pero con OnPush en todos los hijos. Pulsas el botón raíz y ningún hijo parpadea. Hemos cortado las comprobaciones innecesarias — pero ahora la pregunta es: ¿cómo le decimos al componente cuándo sí actualizarse?

OnPush + Signals: granularidad real

Los signals permiten algo que el detector clásico no sabía hacer: Angular conoce exactamente qué parte de la plantilla depende de qué dato.

Combinado con OnPush, esto es lo que se gana:

  • AppComponent mantiene un signal() que se actualiza.
  • Solo lo lee ChildA.
const contador = signal(0);

Pulsas el botón. Solo ChildA se redibuja. ParentComponent y ChildB permanecen estáticos. No es magia; es que Angular ya no necesita revisar nada que no haya pedido el dato.

Llevándolo al mundo real

Un componente que escucha un documento en tiempo real, con OnPush:

<div *ngIf="userDoc$ | async as user">
  <h1>{{ user.name }}</h1>
</div>
@Component({
  selector: 'app-user-profile',
  templateUrl: '...',
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class UserProfileComponent {
  userDoc$ = this.firestore.doc('users/123').valueChanges();

  constructor(private firestore: Firestore) {}
}

El async pipe se encarga de markForCheck() por ti. Con toSignal(), el código queda aún más declarativo — pero no es obligatorio. La regla sigue siendo la misma: cada actualización pasa por un canal que Angular sí reconoce.

Resumen

Pasamos de:

  1. Una app que se comprueba entera cada vez que pasa cualquier cosa (Default).
  2. Una app que solo se comprueba cuando sus entradas cambian (OnPush).
  3. Una app donde Angular sabe exactamente qué pieza redibujar (OnPush + Signals).

Regla práctica: empezar cada componente con OnPush. Relajar la regla cuando duele es más fácil que apretarla después, cuando la app ya está construida sobre suposiciones del Default.

Importante: nada de esto es una promesa de “10x”. Es una decisión técnica sobre cómo se entera Angular de los cambios. Si tu app es lenta por otra razón (red, bundle, layout), el OnPush no la va a arreglar. Pero si el problema está en el árbol de detección, este es el orden en el que vale la pena moverse.