import React from 'react' ; import { useComponentDidMount , useComponentWillUnmount } from "../../hooks/ReactLifecycleHooks" ; import { OnErrorCallback , OnNextCallback , SnapshotSubscriberWithID , SnapshotUnsubscriber , SnapshotSubscriber , SnapshotTuple } from 'polar-shared/src/util/Snapshots' ; import { IDStr } from "polar-shared/src/util/Strings" ; import { isPresent } from "polar-shared/src/Preconditions" ; export interface SubscriptionValue < T > { readonly value : T | undefined ; readonly error : Error | undefined ; } export function useSnapshotSubscriberUsingCallbacks < T > ( subscriber , onNext , onError ? ) { const subscriberIDRef = React . useRef < IDStr > ( subscriber . id ) ; const unsubscriberRef = React . useRef < SnapshotUnsubscriber | undefined > ( undefined ) ; if ( unsubscriberRef . current && subscriberIDRef . current !== subscriber . id ) { unsubscriberRef . current ( ) ; unsubscriberRef . current = undefined ; } if ( ! unsubscriberRef . current ) { const unsubscriber = subscriber . subscribe ( onNext , onError ) ; if ( ! isPresent ( unsubscriber ) ) { console . warn ( "No unsubscriber" ) ; } unsubscriberRef . current = unsubscriber ; } useComponentWillUnmount ( ( ) => { if ( unsubscriberRef . current ) { unsubscriberRef . current ( ) ; } } ) ; } NotStale export function useSnapshotSubscriber < T > ( subscriber ) { const [ state , setState ] = React . useState < SubscriptionValue < T > > ( { value : undefined , error : undefined } ) ; const created = React . useMemo ( ( ) => Date . now ( ) , [ ] ) ; const hasRecordedInitialLatency = React . useRef ( false ) ; function onNext ( value ) { if ( ! hasRecordedInitialLatency . current ) { const lag = Date . now ( ) - created ; if ( lag > 100 ) { console . warn ( `Snapshot subscriber has high latency: id=${ subscriber . id }, lag=${ lag }ms` ) ; } } setState ( { value , error : undefined } ) ; } function onError ( error ) { setState ( { value : undefined , error } ) ; } useSnapshotSubscriberUsingCallbacks ( subscriber , onNext , onError ) ; return state ; } export function useSnapshots < T > ( subscriber ) { const [ state , setState ] = React . useState < SnapshotTuple < T > > ( [ undefined , undefined ] ) ; const unsubscriberRef = React . useRef < SnapshotUnsubscriber | undefined > ( undefined ) ; function onNext ( value ) { setState ( [ value , undefined ] ) ; } function onError ( error ) { setState ( [ undefined , error ] ) ; } useComponentDidMount ( ( ) => { unsubscriberRef . current = subscriber ( onNext , onError ) ; } ) ; useComponentWillUnmount ( ( ) => { if ( unsubscriberRef . current ) { unsubscriberRef . current ( ) ; } } ) ; return state ; }