"Reactividad en Angular: Migración a Input Signals"

Clase 10 de 36Curso de Angular Avanzado

Resumen

La reactividad en Angular ha evolucionado significativamente con la introducción de los Input Signals, una característica que mejora notablemente el rendimiento de las aplicaciones, independientemente de si utilizan server-side rendering o son aplicaciones de formularios, dashboards o backoffice. Esta nueva forma de manejar los datos entre componentes representa un cambio paradigmático en cómo Angular gestiona la reactividad.

¿Qué son los Input Signals y cómo migrar a ellos?

Los Input Signals forman parte del nuevo modelo de reactividad de Angular, diseñado para mejorar el rendimiento de las aplicaciones mediante un enfoque más granular y eficiente. Para entender cómo funcionan, veamos cómo migrar desde el enfoque tradicional.

Anteriormente, definíamos las propiedades de entrada utilizando el decorador @Input():

@Input() duration: number;
@Input() message: string;

Con el nuevo modelo de reactividad, la sintaxis cambia a una forma más declarativa:

duration = input.required<number>();
message = input.required<string>();

Este cambio implica:

  1. Eliminar el decorador @Input()
  2. Utilizar la función input() que proviene de @angular/core (en minúscula, no como el decorador)
  3. Especificar si el input es requerido con .required
  4. Definir el tipo de dato con genéricos <number>, <string>, etc.

Es importante destacar que aunque la implementación interna cambia, la API externa permanece igual. Es decir, seguimos utilizando los mismos nombres de atributos en las plantillas HTML.

Accediendo a los valores de Input Signals

Una diferencia fundamental es cómo accedemos a los valores. Con los Input Signals, ya no accedemos directamente a la propiedad como una variable normal, sino que debemos ejecutarla como una función:

// Antes
console.log(this.duration); // Imprime el valor directamente

// Ahora
console.log(this.duration()); // Debemos ejecutar el signal para obtener su valor

En las plantillas HTML, también necesitamos ejecutar el signal para obtener su valor:

<p>Duration: {{ duration() }}</p>

¿Cómo detectar cambios en los Input Signals?

Angular mantiene retrocompatibilidad con el método tradicional ngOnChanges, pero introduce formas más eficientes y declarativas de reaccionar a los cambios.

Método tradicional (aún compatible)

ngOnChanges(changes: SimpleChanges) {
  if (changes['duration']) {
    console.log('Previous:', changes['duration'].previousValue);
    console.log('Current:', changes['duration'].currentValue);
    this.doSomething();
  }
}

Este enfoque sigue funcionando, pero tiene limitaciones:

  • Un solo método para manejar todos los cambios
  • Código imperativo para verificar qué propiedad cambió
  • Menos legible cuando hay muchos inputs

Nuevo enfoque con effects

constructor() {
  effect(() => {
    // Se ejecuta cada vez que duration cambia
    const value = this.duration();
    this.doSomething();
  });

  effect(() => {
    // Se ejecuta cada vez que message cambia
    const msg = this.message();
    this.doSomethingTwo();
  });
}

Las ventajas de este enfoque son:

  • Granularidad: cada effect se suscribe específicamente a los signals que utiliza
  • Declarativo: el código es más claro y expresa mejor la intención
  • Eficiente: solo se ejecuta cuando los signals específicos cambian

Si necesitamos reaccionar a múltiples signals en un mismo effect:

effect(() => {
  // Se ejecuta si duration O message cambian
  const value = this.duration();
  const msg = this.message();
  this.doSomething();
});

¿Cómo crear valores derivados a partir de Input Signals?

Una de las características más potentes de los signals es la capacidad de crear valores derivados de forma declarativa y eficiente.

Usando effects (enfoque imperativo)

doubleDuration = signal(0);

constructor() {
  effect(() => {
    // Actualiza doubleDuration cuando duration cambia
    this.doubleDuration.set(this.duration() * 2);
  });
}

Usando computed (enfoque declarativo)

doubleDuration = computed(() => this.duration() * 2);

El enfoque con computed es:

  • Más conciso
  • Más declarativo
  • Más eficiente, ya que Angular optimiza automáticamente cuándo recalcular el valor

Es recomendable usar computed para transformaciones de datos y reservar effect para operaciones con efectos secundarios (como llamadas HTTP, manipulación del DOM, etc.).

¿Cuándo utilizar cada enfoque?

  • computed: Para transformar datos de forma reactiva sin efectos secundarios
  • effect: Para ejecutar código con efectos secundarios cuando cambian los signals
  • ngOnChanges: Para mantener compatibilidad con código existente o cuando necesitas comparar valores anteriores y actuales

Los Input Signals representan un avance significativo en el modelo de reactividad de Angular, ofreciendo mejor rendimiento y un código más declarativo. Aunque existe una curva de aprendizaje, los beneficios en términos de rendimiento y mantenibilidad hacen que valga la pena adoptar este nuevo enfoque en tus aplicaciones.

¿Has experimentado con los Input Signals en tus proyectos? ¿Qué otros aspectos de la nueva reactividad de Angular te gustaría explorar? Comparte tus experiencias en los comentarios.