UNPKG

sanity

Version:

Sanity is a real-time content infrastructure with a scalable, hosted backend featuring a Graph Oriented Query Language (GROQ), asset pipelines and fast edge caches

81 lines (70 loc) 2.49 kB
import {useCallback, useMemo} from 'react' import {useMemoObservable} from 'react-rx' import {concat, type Observable, of, Subject} from 'rxjs' import {catchError, concatMap, map, startWith} from 'rxjs/operators' import {usePrevious} from '../../hooks/usePrevious' import {type ReferenceInfo} from './types' const noop = () => undefined const INITIAL_LOADING_STATE: Loadable<ReferenceInfo> = { isLoading: true, result: undefined, error: undefined, retry: noop, } const EMPTY_STATE: Loadable<any> = { isLoading: false, result: undefined, error: undefined, retry: noop, } export type Loadable<T> = | {isLoading: true; result: undefined; error: undefined; retry: () => void} | {isLoading: false; result: T; error: undefined; retry: () => void} | {isLoading: false; result: undefined; error: Error; retry: () => void} type GetReferenceInfo = (id: string) => Observable<ReferenceInfo> export function useReferenceInfo( id: string | undefined, getReferenceInfo: GetReferenceInfo, ): Loadable<ReferenceInfo> { // NOTE: this is a small message queue to handle retries const msgSubject = useMemo(() => new Subject<{type: 'retry'}>(), []) const msg$ = useMemo(() => msgSubject.asObservable(), [msgSubject]) const retry = useCallback(() => { msgSubject.next({type: 'retry'}) }, [msgSubject]) const referenceInfo = useMemoObservable( () => concat(of(null), msg$).pipe( map(() => id), concatMap((refId: string | undefined) => refId ? getReferenceInfo(refId).pipe( map((result) => { return { isLoading: false, result, error: undefined, retry, } as const }), startWith(INITIAL_LOADING_STATE), catchError((err: Error) => { console.error(err) return of({isLoading: false, result: undefined, error: err, retry} as const) }), ) : of(EMPTY_STATE), ), ), [getReferenceInfo, id, msg$, retry], INITIAL_LOADING_STATE, ) // @todo test and see if this were fixed in `react-rx@2.1.x` // workaround for a "bug" with useMemoObservable that doesn't // return the initial value upon resubscription const previousId = usePrevious(id, id) if (id && previousId !== id) { return INITIAL_LOADING_STATE } return referenceInfo }