import { useState } from '@noshiro/react-utils'; import type { InitializedObservable, Observable } from '@noshiro/syncflow'; import { Maybe } from '@noshiro/ts-utils'; import { useEffect, useMemo } from 'react'; export function useObservable( createObservable$: () => InitializedObservable ): InitializedObservable; export function useObservable( createObservable$: () => Observable ): Observable; export function useObservable( createObservable$: () => Observable ): Observable { const s = useMemo(createObservable$, []); useEffect( () => () => { s.complete(); }, [] ); return s; } export const useObservableEffect = ( observable$: Observable, subscriptionFn: (v: A) => void ): void => { useEffect(() => { const s = observable$.subscribe(subscriptionFn); return () => { s.unsubscribe(); }; }, []); }; // Wraps the value with an object to avoid setState's update behavior when T is function type. export function useObservableValue( observable$: Observable, initialValue: B ): A | B; export function useObservableValue(observable$: InitializedObservable): A; export function useObservableValue( observable$: Observable ): A | undefined; export function useObservableValue( observable$: Observable, initialValue?: B ): A | B | undefined { const { state, setState } = useState<{ value: A | B | undefined }>({ value: Maybe.unwrap(observable$.currentValue) ?? initialValue, }); useObservableEffect(observable$, (value) => { setState({ value }); }); return state.value; }