CodeForge

Angular 21 de Cero a Experto / Signals a fondo

Signals: el valor que avisa cuando cambia

Teoría24 min20 XP

Aquí empieza el corazón de Angular 21. Una signal es un contenedor de un valor que, cuando cambia, AVISA a todo lo que dependa de él para que se actualice. Es el equivalente de useState de React, pero de grano más fino y sin re-renderizar componentes enteros. Hoy entiendes qué es una señal, cómo se lee y escribe… y construyes tu propia versión desde cero para ver que no hay magia, solo una idea muy elegante.

El marcador que grita el cambio

Crear, leer y cambiar una señal

contador.component.ts
import { Component, signal } from '@angular/core';

@Component({
selector: 'app-contador',
template: `
  <p>Gastos registrados: {{ cuenta() }}</p>   <!-- se LEE con () -->
  <button (click)="agregar()">Agregar</button>
`,
})
export class ContadorComponent {
cuenta = signal(0);            // crear una señal con valor inicial 0

agregar() {
  this.cuenta.set(this.cuenta() + 1);   // set: reemplazar el valor
  // o: this.cuenta.update(n => n + 1);  // update: derivar del anterior
}
}

Tres operaciones, nada más:

  • Leer: cuenta() —la llamas como función—. En el template {{ cuenta() }}, en la clase this.cuenta(). Ese paréntesis es la clave: al leerla, Angular anota "quien está leyendo ahora depende de esta señal".
  • set(valor): reemplaza el valor por uno nuevo.
  • update(fn): calcula el nuevo valor a partir del actual —como la forma funcional setCuenta(n => n + 1) de React—.

Cuando llamas set o update, la señal notifica a todo lo que la leyó (el template, un computed, un effect) y solo ESO se actualiza.

El puente desde React (y la diferencia clave)

Si vienes de React, esto se parece muchísimo a useState:

comparacion.ts
// React:                          // Angular:
const [cuenta, setCuenta] =        cuenta = signal(0);
useState(0);
cuenta;              // leer       cuenta();          // leer (con paréntesis)
setCuenta(5);        // cambiar    cuenta.set(5);     // cambiar
setCuenta(n => n+1); // derivar    cuenta.update(n => n + 1);

Construye tu propia señal

¿Magia? Para nada. Una señal es un valor guardado en un closure, con una función para leerlo y otra para cambiarlo. Aquí está la versión mínima —el mismo principio que usa Angular por dentro— corriendo en vivo. Léela y ejecútala:

¿Ves lo que pasó? Al leer la señal dentro de un observador, ésta lo GUARDA como dependiente. Al escribir, RECORRE sus dependientes y los vuelve a ejecutar. Eso es todo el sistema reactivo en 15 líneas. Angular añade rendimiento, pereza y detección de ciclos, pero la idea es exactamente ésta: leer registra la dependencia, escribir notifica. Lo profundizarás en las próximas lecciones con computed y effect —y al final del módulo construirás la versión completa—.

¿Por qué una señal se lee llamándola como función, `cuenta()`?

Mini-reto

En el playground, amplía tu señal: 1) crea una señal saldo que empiece en 100000; 2) engancha un observador que imprima `Saldo: ${saldo()}`; 3) haz un par de update que resten gastos (s => s - 4500) y observa cómo el mensaje se reimprime solo con cada cambio. Confirma que NO tuviste que llamar al console.log manualmente tras cada cambio: la señal avisó.

Qué sigue

Tienes el ladrillo básico. Pero el poder real llega al DERIVAR: "el total es la suma de los gastos", "el saldo es el presupuesto menos el total". La próxima lección es computed: una señal calculada a partir de otras que se recalcula sola —y también la construirás desde cero—.