RxJS Interop: Uniendo lo mejor de dos mundos en Angular
Aunque Angular Signals es fantástico para el estado síncrono, RxJS sigue siendo el rey para manejar eventos asíncronos complejos (como debounce, switchMap o websockets). La clave del éxito en Angular moderno es saber cómo hacerlos trabajar juntos.
Angular proporciona el paquete @angular/core/rxjs-interop para facilitar esta comunicación.
De Observable a Signal: toSignal
El uso más común es consumir un flujo de datos (como una petición HTTP) en la vista sin usar el AsyncPipe. toSignal convierte un Observable en un Signal de lectura.
import { toSignal } from '@angular/core/rxjs-interop';
import { inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Component({...})
export class UserListComponent {
private http = inject(HttpClient);
// El observable se suscribe automáticamente
users$ = this.http.get<User[]>('/api/users');
// Convertimos a Signal. Podemos definir un valor inicial.
users = toSignal(this.users$, { initialValue: [] });
}
En la plantilla, simplemente llamamos a users() y Angular se encarga de la reactividad fina.
De Signal a Observable: toObservable
A veces necesitamos reaccionar a cambios en un Signal usando operadores de RxJS (por ejemplo, para hacer un debounce en un input de búsqueda).
import { signal, effect } from '@angular/core';
import { toObservable } from '@angular/core/rxjs-interop';
import { debounceTime, switchMap } from 'rxjs/operators';
export class SearchComponent {
query = signal('');
// Convertimos el signal a observable para usar pipes de RxJS
results$ = toObservable(this.query).pipe(
debounceTime(300),
switchMap(term => this.searchService.search(term))
);
updateQuery(e: Event) {
this.query.set((e.target as HTMLInputElement).value);
}
}
El poder de effect() vs subscribe()
Mientras que en RxJS nos suscribimos manualmente, con Signals usamos effect(). Un efecto se ejecuta siempre que uno de los signals que lee cambia.
- Usa
toSignalpara traer datos a la UI. - Usa
toObservablecuando necesites manipular el tiempo o flujos complejos.
Esta interoperabilidad nos permite eliminar gran parte de la complejidad de gestión de suscripciones manuales (ngOnDestroy o takeUntil).