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;
}