ExamplesSuspense data fetching
Suspense data fetching
useObservablePromise returns a promise for React’s use(). The Suspense
fallback shows until the first emission; later stream updates do not re-trigger
it.
import {Suspense, use, useMemo, useState} from 'react' import {useObservablePromise} from 'react-rx' import {map, timer} from 'rxjs' /** * Simulated API with ~800ms latency. Later ticks update the same stream * without re-triggering the Suspense fallback. */ function createFeed$(id: string) { return timer(800, 2000).pipe( map((n) => ({ id, message: `Update #${n + 1} for ${id}`, at: new Date().toLocaleTimeString(), })), ) } function Feed({id}: {id: string}) { const feed$ = useMemo(() => createFeed$(id), [id]) const promise = useObservablePromise(feed$) const data = use(promise) return ( <div> <h3>{data.id}</h3> <p>{data.message}</p> <small>Last update: {data.at}</small> </div> ) } export default function SuspenseExample() { const [id, setId] = useState('alpha') return ( <div style={{fontFamily: 'system-ui', padding: 16}}> <p> <button type="button" onClick={() => setId('alpha')}> alpha </button>{' '} <button type="button" onClick={() => setId('beta')}> beta </button> </p> <Suspense key={id} fallback={<p style={{opacity: 0.7}}>Loading {id}…</p>} > <Feed id={id} /> </Suspense> <p style={{marginTop: 24, fontSize: 14, opacity: 0.75}}> Switching feeds re-suspends (new observable identity). After the first value, live updates arrive without showing the fallback again. </p> </div> ) }
Last updated on