A hook for integrating RxJS observables with React.
const [value, next, error, complete] = useObservable(obs$ => obs$.pipe( /* ... */ ), 'initial value')
import { useState, useEffect, useMemo, useCallback } from 'react' | |
import { Subject, isObservable } from 'rxjs' | |
function useObservable(generateEnhancedObservable, initValue) { | |
const sub$ = useMemo(() => new Subject(), []) | |
const next = useCallback(sub$.next.bind(sub$), []) | |
const [value, setValue] = useState(initValue) | |
const [error, setError] = useState(null) | |
const [complete, setComplete] = useState(false) | |
useEffect(() => { | |
const obs$ = sub$.asObservable() | |
const enhanced$ = typeof generateEnhancedObservable === 'function' | |
? generateEnhancedObservable(obs$) | |
: obs$ | |
if (!isObservable(enhanced$)) { | |
throw new Error('The function passed to "useObservable" does not return an observable') | |
} | |
const subscription = enhanced$.subscribe({ | |
next: value => { | |
setValue(value) | |
setError(null) | |
}, | |
error: err => setError(err instanceof Error ? err.message : err), | |
complete: () => setComplete(true) | |
}) | |
return () => subscription.unsubscribe() | |
}, []) | |
return [value, next, error, complete] | |
} | |
export default useObservable |