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
62 lines (53 loc) • 1.57 kB
text/typescript
import {useMemoObservable} from 'react-rx'
import {type Observable, of, type OperatorFunction} from 'rxjs'
import {catchError, map} from 'rxjs/operators'
/** @internal */
export type LoadableState<T> = LoadingState | LoadedState<T> | ErrorState
/** @internal */
export interface LoadingState {
value: undefined
error: null
isLoading: true
}
/** @internal */
export interface LoadedState<T> {
value: T
error: null
isLoading: false
}
/** @internal */
export interface ErrorState {
value: undefined
error: Error
isLoading: false
}
const LOADING_STATE: LoadingState = {
isLoading: true,
value: undefined,
error: null,
}
/** @internal */
export function useLoadable<T>(value$: Observable<T>): LoadableState<T | undefined>
/** @internal */
export function useLoadable<T>(value$: Observable<T>, initialValue: T): LoadableState<T>
/** @internal */
export function useLoadable<T>(
value$: Observable<T>,
initialValue?: T,
): LoadableState<T | undefined> {
const initial: LoadableState<T> =
typeof initialValue === 'undefined'
? LOADING_STATE
: {isLoading: false, value: initialValue, error: null}
return useMemoObservable(() => value$.pipe(asLoadable()), [value$], initial)
}
/** @internal */
export function asLoadable<T>(): OperatorFunction<T, LoadableState<T>> {
return (value$: Observable<T>) =>
value$.pipe(
map((value) => ({isLoading: false, value, error: null}) as const),
catchError(
(error): Observable<ErrorState> => of({isLoading: false, value: undefined, error}),
),
)
}