import { computeSelector, isFunction, ObservableReadable, observe, ObserveEvent, ObserveEventCallback, Selector, } from '@legendapp/state'; import { useRef } from 'react'; import type { ObserveOptions } from '../observe'; import { useUnmountOnce } from './useUnmount'; export function useObserve(run: (e: ObserveEvent) => T | void, options?: ObserveOptions): () => void; export function useObserve( selector: Selector, reaction?: (e: ObserveEventCallback) => any, options?: ObserveOptions, ): () => void; export function useObserve( selector: Selector | ((e: ObserveEvent) => any), reactionOrOptions?: ((e: ObserveEventCallback) => any) | ObserveOptions, options?: ObserveOptions, ): () => void { let reaction: ((e: ObserveEventCallback) => any) | undefined; if (isFunction(reactionOrOptions)) { reaction = reactionOrOptions; } else { options = reactionOrOptions; } const ref = useRef<{ selector?: Selector | ((e: ObserveEvent) => T | void) | ObservableReadable; reaction?: (e: ObserveEventCallback) => any; dispose?: () => void; }>({}); ref.current.selector = selector; ref.current.reaction = reaction; if (!ref.current.dispose) { ref.current.dispose = observe( ((e: ObserveEventCallback) => computeSelector(ref.current.selector, e)) as any, (e) => ref.current.reaction?.(e), options, ); } useUnmountOnce(() => { ref.current?.dispose?.(); // @ts-expect-error This is fine to clear the ref to make sure it doesn't run anymore ref.current = undefined; }); return ref.current.dispose; }