import { useEffect, useState, type Dispatch, type SetStateAction, } from 'react'; import { ColdMediatorObservable } from './ColdMediatorObservable'; import { ObservedValues } from '../types'; import { mapObservablesToValues } from '../mapObservablesToValues'; export function useColdObservables>(observables: T): ObservedValues { const [mediator] = useState( () => new ColdMediatorObservable(mapObservablesToValues(observables) as T), ); const [values, setValues] = useState(() => mediator.value as ObservedValues); useEffect(() => { const unsubscribers = subscribeMediatorToObservables(observables, mediator); const unsubscribeFromMediator = mediator.subscribe(setValues); reconcileStateWithMediatorAfterResume(setValues, mediator); syncMediatorWithObservableValues(observables, mediator); return () => { unsubscribers.forEach((unsubscribe) => unsubscribe()); unsubscribeFromMediator(); }; }, []); return values; } function subscribeMediatorToObservables>( observables: T, mediator: ColdMediatorObservable, ) { return Object.keys(observables as {}).map((key) => { return observables[key].subscribe(((value: T[typeof key]) => mediator.setValue(key, value))); }); } function syncMediatorWithObservableValues>( observables: T, mediator: ColdMediatorObservable, ) { (Object.keys(observables as {}) as Array).forEach((key) => { mediator.setValue(key, observables[key].value); }); } function reconcileStateWithMediatorAfterResume>( setValues: Dispatch>>, mediator: ColdMediatorObservable, ) { setValues((currentValues) => ( Object.is(currentValues, mediator.value as ObservedValues) ? currentValues : mediator.value as ObservedValues )); }