Primitivas reactivas de Angular: Uso de Linked Signal y Computed
Clase 13 de 36 • Curso de Angular Avanzado
Contenido del curso
Gestión de Entornos
Nuevas Funcionalidades en Angular
- 7

Buenas prácticas con variables locales en Angular
09:14 min - 8

Optimización de Imágenes en Angular con NG Optimizate Image
17:08 min - 9

Optimización de Rutas Amigables para SEO en Angular
11:27 min - 10

"Reactividad en Angular: Migración a Input Signals"
20:42 min - 11

Migración de Inputs a Signals en Angular: Mejora de Rendimiento y Flujo
12:24 min - 12

Migración de Outputs en Angular: De Decoradores a Funciones
07:35 min - 13

Primitivas reactivas de Angular: Uso de Linked Signal y Computed
Viendo ahora - 14

Sincronización de Componentes en Angular con Model y Signals
12:03 min - 15

Interoperabilidad de RXJS y Signals en Angular
11:18 min - 16

Conversión de Observables a Signals en Angular con toSignal
08:07 min - 17

Interoperabilidad de RXDS y Signals en Angular: Uso de RX Resourcers
11:10 min - 18

Manejo de Parámetros Reactivos con RX Resource en Angular
09:18 min - 19

Manejo de Promesas y Fetch en Angular sin RXJS
07:59 min - 20

Reactividad en Angular: Uso de Signals para Consultas DOM
09:00 min - 21

Configuración de Prettier para HTML en Angular
05:28 min
Server-Side Rendering (SSR) y Navegación
- 22

Server Side Rendering en Angular: Builders y Migración
10:17 min - 23

Server Side Rendering con Angular: Mejora Rendimiento y SEO
13:26 min - 24

Manejo de APIs del Navegador con Angular: Uso de AfterNextRender
09:43 min - 25

Geolocalización y APIs: Creando un Mapa de Tiendas Cercanas
15:39 min - 26

Habilitar Pre-rendering en Angular para Generación de Sitios Estáticos
11:26 min - 27

Despliegue de Aplicaciones Node.js con App Fiber Hosting
18:12 min
Optimización de Rendimiento
- 28

Generación de Meta Tags Dinámicos con Angular y Open Graph
15:11 min - 29

Creación de MetaTags Dinámicos en Angular
12:51 min - 30

Proceso de Hydration y Event Replay en Angular
05:54 min - 31

Implementación de Productos Relacionados en Angular eCommerce
09:26 min - 32

Carga diferida de componentes en Angular para mejorar rendimiento
10:10 min - 33

Optimización de Incremental Hydration en Angular
06:14 min - 34

Configuración de Server Routing en Angular
10:43 min - 35

Aplicaciones Sin Zone.js: Migración a Signals en Angular
13:02 min - 36

Despliegue y Reactividad Avanzada en Angular
00:53 min
La programación reactiva en Angular ha evolucionado significativamente con la introducción de primitivas como signals, computed y effects. Estas herramientas permiten crear aplicaciones más eficientes y con un código más declarativo. En esta ocasión, exploraremos una nueva primitiva llamada "writableComputed" (o linkedSignal), que resuelve algunas limitaciones comunes y mejora la experiencia de desarrollo manteniendo el rendimiento óptimo de nuestra aplicación.
¿Qué son las primitivas reactivas en Angular?
Angular ha desarrollado tres primitivas fundamentales para el manejo de estado reactivo:
- Signal: Permite declarar un estado de forma explícita y declarativa
- Computed: Crea un signal derivado que depende de otro signal
- Effect: Ejecuta funciones cuando detecta cambios en un signal
Aunque estas primitivas son poderosas, existen situaciones donde presentan limitaciones. Por ejemplo, una regla no escrita en Angular es evitar el uso excesivo de effects, ya que generalmente existen mejores alternativas. Aquí es donde entra en juego el linkedSignal (writableComputed).
¿Cómo funciona el writableComputed en un caso práctico?
Para entender mejor esta nueva primitiva, trabajaremos con un componente de detalle de producto que incluye un carrusel de imágenes. El objetivo es mejorar la implementación actual haciéndola más declarativa y eficiente.
Analicemos primero el código original:
// Implementación original
this.productService.getOne(id)
.subscribe(data => {
this.product.set(data);
if (data.images.length > 0) {
this.cover.set(data.images[0]);
}
});
En este código, cuando obtenemos los datos del producto, establecemos el producto en un signal y luego, si el producto tiene imágenes, establecemos la primera imagen como portada (cover).
Mejorando con computed
Podemos mejorar este código utilizando un computed, ya que la portada se deriva del producto:
// Usando computed
this.cover = computed(() => {
const product = this.product();
return product?.images?.[0] ?? '';
});
O de forma más explícita:
this.cover = computed(() => {
const product = this.product();
if (product && product.images.length > 0) {
return product.images[0];
}
return '';
});
Esta implementación es más declarativa, pero presenta un problema: no podemos modificar directamente un computed. Esto se convierte en un inconveniente cuando necesitamos cambiar la imagen de portada al hacer clic en una miniatura del carrusel:
// Esto no funcionaría con un computed
changeImage(image: string) {
this.cover.set(image); // Error: computed no tiene método set
}
La solución con writableComputed (linkedSignal)
Para resolver este problema, Angular introdujo el writableComputed (también conocido como linkedSignal), que combina las ventajas de computed con la capacidad de modificar su valor:
import { writableComputed } from '@angular/core';
// Usando writableComputed
this.cover = writableComputed(() => {
const product = this.product();
return product?.images?.[0] ?? '';
});
// Ahora podemos hacer esto sin problemas
changeImage(image: string) {
this.cover.set(image); // Funciona correctamente
}
Con esta implementación, obtenemos lo mejor de ambos mundos: un valor derivado que se actualiza automáticamente cuando cambia el producto, pero que también podemos modificar directamente cuando sea necesario.
¿Cómo acceder al valor anterior con writableComputed?
Una característica adicional del writableComputed es la capacidad de acceder al valor anterior. Esto se logra utilizando una sintaxis alternativa:
this.cover = writableComputed({
source: this.product, // El signal del que depende (sin paréntesis)
computation: (product, previousValue) => {
// Si no hay imágenes, mantener el valor anterior
if (!product || product.images.length === 0) {
return previousValue;
}
return product.images[0];
}
});
Esta forma de declaración nos da acceso al valor anterior (previousValue), lo que puede ser útil en escenarios donde queremos mantener cierta información o realizar comparaciones con el estado previo.
Mejorando la estructura del código
Para mantener un código limpio y evitar confusiones, es recomendable seguir convenciones de nomenclatura. Una práctica común es añadir un prefijo $ a las variables que son signals:
// Usando convención de nomenclatura
this.$product = signal<Product | null>(null);
this.$cover = writableComputed(() => {
const product = this.$product();
return product?.images?.[0] ?? '';
});
// En el template
<div *ngIf="$product() && $cover()">
<img [src]="$cover()" alt="Product cover">
</div>
Esta convención hace que sea más fácil identificar qué variables son signals y evita conflictos de nombres.
El writableComputed (linkedSignal) es una herramienta poderosa que nos permite crear código más declarativo y eficiente en Angular, combinando las ventajas de los computed signals con la flexibilidad de poder modificar su valor directamente. ¿Has utilizado ya esta primitiva en tus proyectos? ¿Qué otras situaciones crees que podrían beneficiarse de su uso? Comparte tu experiencia en los comentarios.