¿Qué es un Computed Signal?
Imagina que estás construyendo un carrito de compras. Tienes una señal para el precio del producto y otra para el porcentaje de descuento. El precio final es el resultado de calcular ambas variables.
En lugar de recalcular manualmente el precio final cada vez que cambie el descuento, puedes usar computed signal. Un computed signal es una señal de solo lectura que deriva su valor a partir de otros signals.
TypeScript:
import { signal, computed } from '@angular/core';
// Creamos los signals editables.
precioBase = signal(100); //Precio del producto.
porcentajeDescuento = signal(10); // Descuento 10%.
// Creamos una señal que reaccionará a los signals usando computed()
precioFinal = computed(() => {
const precio = this.precioBase();
const descuento = (precio * this.porcentajeDescuento()) / 100;
return precio - descuento;
});
Aquí el precioFinal depende directamente de los signals precioBase y procentajeDescuento. Cada vez que algun signal cambie, Angular sabrá automáticamente que el valor de precioFinal también debe actualizarse.
Caracteristicas de computed() que debes saber:
1. Son de Solo Lectura (Read-only)
Un computed signal protege tu lógica. Como su valor se calcula automáticamente, no puedes modificarlo directamente. Si lo intentas saldrá un error de compilación:
precioFinal.set(5); // ERROR DE COMPILACIÓN
Esto es excelente para los nuevos desarrolladores porque evita que alteren accidentalmente datos que deberían ser calculados de forma pura.
2. Evaluación Perezosa (Lazy) y Memoización (Caché)
¿Qué significan estos términos tan raros?
-
Evaluación perezosa: La función dentro de tu computed() no se ejecutará hasta la primera vez que intentes leer su valor por ejemplo, al mostrarlo en el HTML:
<p><strong>Total a pagar: ${{ precioFinal() }}</strong></p> - Memorización: Una vez calculado el valor, Angular lo guarda en una memoria caché. Si vuelves a leer precioFinal () cinco veces seguidas, Angular te devolverá el valor guardado de inmediato, todo esto sin volver a hacer la multiplicación.
Solo cuando el signal de origen porcentajeDescuento o precioBase cambie, Angular marcará la caché como inválida y volverá a calcular el valor la próxima vez que se lea. Gracias a esto, puedes hacer operaciones costosas como filtrar arreglos gigantescos dentro de un computed sin miedo a ralentizar tu app.
3. Dependencias Dinámicas.
Angular no asume qué señales necesitas; rastrea únicamente las señales que realmente se ejecutaron mientras corría la función.
Imagina que en tu tienda tienes clientes Premium que tienen envío gratuito, y clientes normales que pagan una tarifa de envío que puede cambiar dependiendo de su ubicación.
TypeScript:
import { signal, computed } from '@angular/core';
const esUsuarioPremium = signal(true);
const subtotal = signal(100);
const costoEnvio = signal(15); // El envío base es de 15.
const totalConEnvio = computed(() => {
if (esUsuarioPremium()) {
return subtotal(); // ¡Envío gratis! No necesita leer el signal costoEnvio.
} else {
// Si el usuario no es premium se lee el signal costoEnvio.
return subtotal() + costoEnvio();
}
});
Al entra al primer bloque del if y devuelve el subtotal. Como la señal costoEnvio() nunca se llegó a leer, Angular no la registra como una dependencia.
En el momento en que cambies esUsuarioPremium() a false, Angular volverá a ejecutar la función, leerá costoEnvio() y a partir de ese instante añade el costo de envio como una nueva dependencia.
Buenas Prácticas para no romper tu código.
Es fácil caer en algunas trampas comunes con las Signals cuando recién estas empezando. Grábate estas tres reglas:
- Debe ser una función pura: El único propósito de un computed es calcular y retornar un nuevo valor. Nunca intentes modificar el DOM, cambiar otras variables o alterar otras señales dentro de un computed.
- Prohibido el código asíncrono: Las Signals en Angular son estrictamente síncronas. No metas setTimeout, promesas (Promise) o peticiones HTTP dentro de un computed(). No funcionará como esperas ya que Angular perderá el hilo de qué señales se ejecutaron.
- Usa computed() en lugar de effect() para transformar datos: Si ves que estás usando un effect() para escuchar un cambio en una señal y luego usar un .set() en otra señal. Lo que necesitas es refactorizarlo a un computed()
CONCLUSIÓN
Cada vez que necesites generar datos que dependan directamente de otra información en tu aplicación, tu mejor opción es usar computed(). Te permite crear un estado derivado de forma automática y sin complicaciones.
Una de sus mayores ventajas es la velocidad, ya que guarda los resultados en una memoria caché para evitar cálculos repetidos e innecesarios. Además, te brinda mucha seguridad al programar, porque al ser de solo lectura, tienes la garantía de que nadie podrá modificar su valor por accidente.
Por último, para que todo funcione a la perfección, debes asegurarte de mantener el código dentro de esta función completamente síncrono y libre de efectos secundarios. Tu único objetivo aquí debe ser procesar la información y devolver el nuevo resultado.
- Debes estar logueado para realizar comentarios