Interoperabilidad de RXJS y Signals en Angular
Clase 15 de 36 • Curso de Angular Avanzado
Resumen
La integración de Signals con RXJS en Angular representa una evolución significativa en el manejo de la reactividad. Esta nueva funcionalidad permite aprovechar el código existente basado en observables mientras se adopta el moderno patrón de Signals, ofreciendo una transición suave y eficiente para los desarrolladores de Angular.
¿Cómo integrar RXJS y Signals con toSignal?
Angular reconoce que muchos desarrolladores tienen una gran cantidad de código basado en RXJS, el patrón de observabilidad que ha sido fundamental en versiones anteriores. Con la introducción de Signals, surge la necesidad de una interoperabilidad entre ambos enfoques. La función toSignal()
es la respuesta a esta necesidad, permitiendo convertir observables en signals sin tener que reescribir todo el código existente.
La clave para utilizar correctamente esta función es entender qué tipo de observable estamos manejando:
- Observables con valor inicial: Como los
BehaviorSubject
, que ya contienen un valor desde su creación - Observables sin valor inicial: Como los
Subject
simples, que emiten valores solo después de una acción específica
Convirtiendo observables con valor inicial
Cuando trabajamos con observables que ya tienen un valor inicial, la conversión es bastante directa:
import { toSignal } from '@angular/core/rxjs-interop';
import { BehaviorSubject } from 'rxjs';
// Observable con valor inicial
const observableWithInit = new BehaviorSubject<string>('init value');
// Conversión a Signal (modo síncrono)
const signalWithInit = toSignal(observableWithInit);
En este caso, el signal creado se sincronizará automáticamente con el valor inicial del observable. No es necesario proporcionar un valor inicial adicional ya que el observable ya lo tiene.
Convirtiendo observables sin valor inicial
Para observables que no tienen un valor inicial, debemos proporcionar uno explícitamente:
import { toSignal } from '@angular/core/rxjs-interop';
import { Subject, delay } from 'rxjs';
// Observable sin valor inicial
const observableWithoutInit = new Subject<string>();
// Conversión a Signal con valor inicial explícito
const signalWithoutInit = toSignal(observableWithoutInit.pipe(
delay(3000) // Simulando una demora en la emisión
), { initialValue: '---' });
En este escenario, el parámetro initialValue
es crucial porque los signals siempre necesitan un valor inicial, a diferencia de algunos observables.
¿Cuándo y por qué utilizar toSignal en proyectos Angular?
La función toSignal()
resulta especialmente útil en situaciones donde:
- Tienes servicios existentes basados en RXJS: Particularmente servicios HTTP que devuelven observables
- Quieres adoptar Signals gradualmente: Sin necesidad de reescribir toda la lógica de tu aplicación
- Necesitas interoperabilidad entre paradigmas: Permitiendo que partes de tu aplicación usen observables mientras otras usan signals
La ventaja principal es que puedes mantener toda tu lógica de negocio en observables mientras aprovechas las características de los signals en tus componentes, como la integración con computed()
o el uso en plantillas sin necesidad de pipes async.
Ejemplo práctico de interoperabilidad
Veamos cómo podemos emitir valores a nuestros observables y ver la sincronización automática con los signals:
// Métodos para emitir valores
emitWithInit() {
this.observableWithInit.next('new value');
}
emitWithoutInit() {
this.observableWithoutInit.next('***');
}
En la plantilla HTML, podemos usar directamente los signals sin preocuparnos por la suscripción o el ciclo de vida:
<div>
<p>Signal con valor inicial: {{ signalWithInit() }}</p>
<button (click)="emitWithInit()">Emitir nuevo valor</button>
</div>
<div>
<p>Signal sin valor inicial: {{ signalWithoutInit() }}</p>
<button (click)="emitWithoutInit()">Emitir nuevo valor</button>
</div>
Cuando hacemos clic en los botones, los valores emitidos por los observables se reflejan automáticamente en los signals, demostrando la sincronización perfecta entre ambos paradigmas.
Aplicaciones prácticas en servicios HTTP
Una de las aplicaciones más comunes de toSignal()
será con los servicios HTTP, que por naturaleza devuelven observables:
// En un servicio
getProducts(): Observable<Product[]> {
return this.http.get<Product[]>('/api/products');
}
// En un componente
products = toSignal(this.productService.getProducts(), { initialValue: [] });
Este enfoque permite seguir utilizando el HttpClient de Angular tal como está, mientras aprovechamos la simplicidad de los signals en nuestros componentes.
La función toSignal()
representa un puente perfecto entre el pasado y el futuro de la reactividad en Angular, permitiendo una adopción gradual y pragmática de los nuevos patrones sin sacrificar el código existente. ¿Has comenzado a integrar Signals en tus proyectos con código RXJS existente? Comparte tu experiencia y las estrategias que has utilizado para esta transición.