La reactividad en Angular es el proceso mediante el cual el framework determina que el estado de la aplicación ha cambiado y, si es necesario, refresca la vista o el DOM. Si has leído el artículo Estrategia de detección de cambios, la magia de Angular sabrás que Angular basa esta detección en un árbol de componentes y en mecanismos como NgZone o ChangeDetectionStrategy para controlar cuándo y cómo se actualiza la UI.

Hoy vamos a ir un paso más allá: veremos cómo Angular Signals, la nueva API de reactividad en Angular introducida de forma experimental en Angular 16, permite mejorar la eficiencia de la UI, actualizar solo lo necesario y simplificar la gestión del estado en componentes Angular, optimizando el rendimiento de tus aplicaciones.

El problema con la detección de cambios clásica en Angular

En el enfoque tradicional:

  • Cada componente tiene su propio detector de cambios.
  • Angular recorre el árbol de componentes cada vez que ocurre un evento asíncrono (click, timer, petición HTTP).
  • En aplicaciones con muchos componentes o listas grandes, esto genera ciclos de detección de cambios innecesarios, afectando el rendimiento.

Por ejemplo, en el artículo anterior creamos un reloj que se actualiza cada segundo y una tabla de usuarios. La actualización del reloj disparaba un ciclo completo de detección de cambios en Angular, recalculando valores aleatorios en cada fila aunque los datos no hubieran cambiado. Puedes encontrar la aplicación en el siguiente enlace. Sigue leyendo para descubrir cómo aplicaremos Angular Signals en este ejemplo.

Angular Signals: cómo mejora la reactividad

Con Angular Signals:

  • Cada signal representa un valor reactivo.
  • Angular actualiza solo los bindings que dependen de ese signal.
  • Los valores derivados (computed) se recalculan automáticamente.
  • No se necesita ChangeDetectionStrategy.OnPush ni ChangeDetectorRef para optimizar.

Esto convierte a Signals en una herramienta clave para mejorar el rendimiento en Angular, especialmente en aplicaciones grandes con listas y componentes complejos.

Señales, efectos y valores derivados

Para entenderlo mejor, veamos cómo funcionan los Signals en Angular.

Crear un signal

import { signal } from '@angular/core';

const counter = signal(0);
  • Un signal representa un valor reactivo.
  • Para leerlo, se invoca como una función: counter().
  • Para escribir en él, se usa .set() o .update().

Efectos (effect)

Los efectos son funciones que se ejecutan automáticamente cuando los signals que usan cambian.

import { signal, effect } from '@angular/core';
const counter = signal(0);
effect(() => {
  console.log(`El contador vale ${counter()}`);
});
counter.set(1); // Se ejecuta el effect y muestra “El contador vale 1”

Valores derivados (computed)

Puedes derivar un valor de uno o varios signals sin necesidad de reescribir lógica adicional.

import { computed } from '@angular/core';

const double = computed(() => counter() * 2);
  • Cuando counter cambia, Angular recalcula automáticamente double.
  • computed es de solo lectura, no se puede modificar manualmente.

Características avanzadas de Angular Signals

Además de lo que hemos visto, Angular Signals tiene varias características importantes según la documentación oficial:

Computed es lazy y memorizado

  • No se ejecuta hasta que alguien lo lee.
  • Memoriza su último valor.
  • Solo se recalcula si cambia alguna dependencia.
const counter = signal(0);
const double = computed(() => {
  console.log('Recalculando...');
  return counter() * 2;
});
  • Si nunca llamas a double(), la función no se ejecuta.

Seguimiento dinámico de dependencias

Angular trackea solo los signals que realmente se leen dentro de un computed o effect.

const show = signal(false);
const counter = signal(0);

const conditional = computed(() => show() ? counter() : 0);
  • Mientras show() sea false, conditional no depende de counter.
  • Esto optimiza el rendimiento y evita recálculos innecesarios.

Signals en templates

{{ counter() }}
  • Angular detecta automáticamente que la plantilla depende del signal.
  • La UI se actualiza solo cuando cambia el valor.
  • No necesitas async pipe, ChangeDetectorRef ni markForCheck.

untracked(): evitar dependencias reactivas

Permite leer un signal sin que se registre como dependencia dentro de un effect o computed.

effect(() => {
  console.log(`User set to ${currentUser()} and the counter is ${untracked(counter)}`);
});
  • El efecto solo se ejecuta cuando cambia currentUser.
  • Cambios en counter no disparan el efecto, pero todavía podemos leer su valor actual.
  • Esto es útil cuando quieres leer datos de manera incidental sin convertirlos en triggers para la reactividad.

Ejemplo práctico en vivo: reloj y tabla de usuarios con Angular Signals

Caso real angular signals

En lugar de mostrar todo el código aquí, hemos preparado un ejemplo interactivo en StackBlitz para que puedas ver Angular Signals funcionando en tiempo real.

En este ejemplo podrás observar:

  • Un reloj que se actualiza cada segundo.
  • Una tabla de usuarios donde cada fila depende de un signal, evitando actualizaciones innecesarias.
  • Cómo la UI se actualiza solo cuando cambia el estado relevante, mejorando el rendimiento frente a la detección de cambios clásica.

Prueba el ejemplo en vivo en StackBlitz.

Comparativa visual

Antes (Default CD) Ahora (Signals)
Ciclo completo de detección de cambios cada segundo Solo se actualiza lo que depende de un signal
randomId se recalculaba innecesariamente randomId permanece estable
Necesidad de OnPush para optimizar No se necesita OnPush ni ChangeDetectorRef
Rendimiento afectado con muchas filas Rendimiento constante aunque la hora cambie

Conclusión

Angular Signals representa la evolución del modelo de detección de cambios explicado en nuestro artículo anterior.

Antes, cualquier evento asíncrono podía disparar un ciclo completo de detección de cambios. Ahora, Angular actualiza solo los bindings que dependen de los signals que cambian, evitando cálculos innecesarios y mejorando la eficiencia.

Con Signals y valores derivados (computed), podemos construir aplicaciones más rápidas, predecibles y fáciles de mantener, especialmente cuando el árbol de componentes crece.

Cuéntanos qué te parece.

Los comentarios serán moderados. Serán visibles si aportan un argumento constructivo. Si no estás de acuerdo con algún punto, por favor, muestra tus opiniones de manera educada.