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);
users$ = this.http.get<User[]>('/api/users');
users = toSignal(this.users$, { initialValue: [] });
}
toSignal se suscribe automáticamente al Observable y se desuscribe cuando el componente se destruye.
De Signal a Observable: toObservable
import { signal } from '@angular/core';
import { toObservable, toSignal } from '@angular/core/rxjs-interop';
import { debounceTime, distinctUntilChanged, switchMap, catchError } from 'rxjs/operators';
import { of } from 'rxjs';
export class SearchComponent {
private searchService = inject(SearchService);
query = signal('');
private results$ = toObservable(this.query).pipe(
debounceTime(300),
distinctUntilChanged(),
switchMap(term =>
term.length < 2
? of([])
: this.searchService.search(term).pipe(
catchError(() => of([]))
)
)
);
results = toSignal(this.results$, { initialValue: [] });
}
takeUntilDestroyed: El destructor automático
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
export class NotificationComponent {
private destroyRef = inject(DestroyRef);
ngOnInit() {
interval(5000).pipe(
takeUntilDestroyed(this.destroyRef),
switchMap(() => this.notificationService.check())
).subscribe(notifications => {
// Se cancela automáticamente al destruir el componente
});
}
}
El poder de effect() vs subscribe()
- Usa
toSignalpara traer datos a la UI. - Usa
toObservablecuando necesites manipular el tiempo o flujos complejos. - Usa
takeUntilDestroyedcuando trabajes con suscripciones imperativas.
Esta interoperabilidad nos permite eliminar gran parte de la complejidad de gestión de suscripciones manuales (ngOnDestroy o takeUntil).