Volver al blog
Imagen de portada del artículo: RxJS Interop: Uniendo lo mejor de dos mundos en Angular

RxJS Interop: Uniendo lo mejor de dos mundos en Angular

Aprende a conectar Observables y Signals utilizando el paquete @angular/core/rxjs-interop para manejar asincronía compleja de forma sencilla.

13 min
German

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()

Esta interoperabilidad nos permite eliminar gran parte de la complejidad de gestión de suscripciones manuales (ngOnDestroy o takeUntil).