import { DefaultedStateObservable, liftEffects, StateObservable, SUSPENSE, } from "@rx-state/core" import { useRef, useState } from "react" import useSyncExternalStore from "./internal/useSyncExternalStore" import { useSubscription } from "./Subscribe" type VoidCb = () => void interface Ref { source$: StateObservable args: [(cb: VoidCb) => VoidCb, () => Exclude] } export const useStateObservable = ( source$: StateObservable, ): Exclude => { const subscription = useSubscription() const [, setError] = useState() const callbackRef = useRef>() if (!callbackRef.current) { const getValue = (src: StateObservable) => { const result = src.getValue() if (result instanceof Promise) throw result return result as any } const gv: () => Exclude = () => { const src = callbackRef.current!.source$ as DefaultedStateObservable if (!src.getRefCount() && !src.getDefaultValue) { if (!subscription) throw new Error("Missing Subscribe!") subscription(src) } return getValue(src) } callbackRef.current = { source$: null as any, args: [, gv] as any, } } const ref = callbackRef.current if (ref.source$ !== source$) { ref.source$ = source$ ref.args[0] = (next: () => void) => { const subscription = liftEffects()(source$).subscribe({ next, error: (e) => { setError(() => { throw e }) }, }) return () => { subscription.unsubscribe() } } } return useSyncExternalStore(...ref!.args) }