Buscador

Volver al blog

El Renacimiento de Angular: De Componentes a Señales

Avatar
Emmanuel Luján
6 min de lectura

El Renacimiento de Angular: De Componentes a Señales

Tabla de Contenidos

Abrir tabla de contenidos

La Era de Zone.js: Magia a un Costo

Históricamente, Angular ha dependido de Zone.js para saber cuándo actualizar la vista. Esto no necesariamente es malo, pero tiene sus desventajas, a lo largo de este post analizaremos a fondo el porqué de este cambio.

¿Cómo funciona el flujo tradicional?

Zone.js crea un “contexto” alrededor de todas las operaciones asíncronas (clicks, HTTP requests, timeouts). Cuando algo sucede, Zone.js le avisa a Angular: “Oye, algo pasó, checa todo”.


El Surgimiento de las Signals: Reactividad de Grano Fino

Las Signals (introducidas a partir de la v16) cambian el paradigma: en lugar de que Angular “adivine” si hubo cambios, el dato mismo es el que le avisa a Angular.

¿Qué es una Signal?

Imagina una Signal como un “contenedor” de un valor que mantiene una lista de quién lo está usando (suscriptores).

La Mecánica Interna: El Grafo de Dependencias

A diferencia de los Observables de RxJS, las Signals no requieren que te suscribas manualmente (evitas el | async o los .subscribe()). Angular crea un grafo de dependencias de forma automática. Si una Signal cambia, Angular sabe exactamente qué parte del DOM debe actualizarse sin tener que recorrer todo el árbol de componentes.


Comparativa Técnica: Flujo Tradicional vs. Signals

CaracterísticaFlujo Tradicional (Zone.js)Flujo Reactivo (Signals)
DetecciónBasada en eventos asíncronos.Basada en cambios de estado específicos.
GranularidadDe arriba hacia abajo (Árbol completo).Grano fino (Solo lo afectado).
RendimientoConsume más CPU en apps complejas.Optimizado; evita comparaciones innecesarias.
DX (Experiencia Dev)Más “mágica” pero difícil de debuguear.Más explícita y predecible.

¿Por qué es la tendencia actual? (El camino a Zoneless)

La meta final de Angular es ser Zoneless. Al usar Signals, podemos eventualmente quitar Zone.js de nuestros polyfills.ts.

Ventajas de esta tendencia:


Implementación en el Código

Implementar una signal es muy sencillo, basta con usar la función signal() de Angular. A continuación te muestro un ejemplo de cómo implementar una signal en Angular.

// Antes (Tradicional)
count = 0;
increment() { this.count++; }

// Ahora (Signals)
count = signal(0);
doubleCount = computed(() => this.count() * 2); // Se actualiza solo si count cambia

increment() {
  this.count.update(v => v + 1);
}

La Sinergia: RxJS + Signals

Aunque las Signals manejan la reactividad en la vista de forma asombrosa, RxJS sigue siendo el rey para manejar flujos asíncronos complejos (como peticiones HTTP, WebSockets o debounce de inputs). La clave está en el paquete @angular/core/rxjs-interop.

1. De Observable a Signal: toSignal()

Este es el caso más común: recibes datos de una API (Observable) y quieres mostrarlos en la UI de forma eficiente sin usar el pipe async.

// En tu servicio o componente
users$ = this.http.get<User[]>('/api/users');
users = toSignal(this.users$, { initialValue: [] }); 

// En el template ya no usas el pipe async:
// <ul> @for (user of users(); track user.id) { ... } </ul>

2. De Signal a Observable: toObservable()

A veces necesitas reaccionar a un cambio de una Signal para disparar un efecto secundario asíncrono, como una búsqueda en la base de datos cada que un filtro cambia.

query = signal('');
// Convertimos la signal a observable para usar operadores de RxJS
results$ = toObservable(this.query).pipe(
  debounceTime(300),
  distinctUntilChanged(),
  switchMap(q => this.userService.search(q))
);

¿Cuándo usar qué?

Es de suma importancia saber cuando usar cada una de estas herramientas, ya que no son excluyentes, sino complementarias. A continuación te muestro una tabla comparativa para que puedas tomar la mejor decisión.

EscenarioHerramienta IdealRazón
Estado de la UISignalsSíncronas, simples, sin suscripciones manuales y performance de grano fino.
Eventos AsíncronosRxJSManejo de tiempo, reintentos (retry), cancelación y composición de streams.
Derivación de datosSignals (computed)Se ejecutan de forma perezosa (lazy) y solo cuando es necesario.
Orquestación de APIsRxJSLos operadores como combineLatest o forkJoin son mucho más potentes para esto.

El concepto Pro: effect() vs tap()

En RxJS usamos tap() para efectos secundarios dentro de un stream. En el mundo de las Signals, tenemos effect().

Un effect() se ejecuta al menos una vez y luego cada vez que cualquier Signal leída dentro de él cambia. Es perfecto para:

Ojo aquí: No uses effect() para cambiar otros estados (Signals), porque podrías crear ciclos infinitos. Para eso existe computed().


Conclusión

Las Signals no mataron a RxJS; al contrario, lo liberaron de la carga de tener que gestionar la renderización de la UI, permitiéndole brillar en lo que mejor hace: gestionar flujos de datos complejos en el tiempo.

Las Signals no son solo un “feature” nuevo, sino los cimientos sobre los que Angular se está reconstruyendo para competir en rendimiento con frameworks como Solid.js o Qwik, pero manteniendo su robustez empresarial.