Integrar programación reactiva (RxJS/Observables) en componentes de React de forma declarativa y reutilizable, permitiendo:
- Suscripción automática con
useEffect
- Encapsulamiento de lógica en una función utilitaria (
useObservable
) - Desuscripción automática al desmontar el componente
- Integración sencilla con Firebase Auth o cualquier otro observable
import { useEffect } from 'react';
import { Observable, Subscription } from 'rxjs';
export function useObservable<T>(
observable$: Observable<T>,
next: (value: T) => void,
deps: any[] = []
) {
useEffect(() => {
const subscription: Subscription = observable$.subscribe({
next,
error: (err) => console.error('Observable error:', err),
});
return () => subscription.unsubscribe();
}, deps);
}
import { Observable } from 'rxjs';
import { onAuthStateChanged } from 'firebase/auth';
function authStateObservable(auth: any): Observable<any> {
return new Observable((subscriber) => {
const unsubscribe = onAuthStateChanged(auth, (user) => {
subscriber.next(user);
});
return unsubscribe;
});
}
import { useState } from 'react';
import { auth } from './firebase';
import { useObservable } from './useObservable';
function MyComponent() {
const [user, setUser] = useState(null);
const observable$ = authStateObservable(auth);
useObservable(observable$, setUser, []);
return (
<div>
{user ? <p>Logged in as {user.email}</p> : <p>Not logged in</p>}
</div>
);
}
Puedes usar operadores como combineLatest
, switchMap
, etc.
import { combineLatest } from 'rxjs';
import { map } from 'rxjs/operators';
const combined$ = combineLatest([observable1$, observable2$]).pipe(
map(([a, b]) => ({ a, b })),
);
useObservable(combined$, (data) => {
// manejar el nuevo estado combinado
}, []);
- Reutilizable: el hook sirve con cualquier observable
- Declarativo: el componente solo declara la fuente y qué hacer con los datos
- Seguro: el
unsubscribe
se maneja automáticamente - Escalable: permite componer múltiples fuentes de datos reactivas fácilmente
Este hook podría ampliarse para incluir:
- Estados
loading
,error
- Soporte para operadores comunes (
filter
,debounceTime
, etc.) - Integración con
useSyncExternalStore
en React 18+