UNPKG

@equinor/fusion-observable

Version:
40 lines 1.73 kB
import { useCallback, useMemo, useState } from 'react'; import { from, Subject } from 'rxjs'; import { debounce, debounceTime, switchMap, tap } from 'rxjs/operators'; /** * React hook that debounces calls to a function and exposes the results as * an observable stream. * * Returns a `next` function (the debounced trigger), a `value$` observable * that emits results, and an `idle` flag indicating whether a debounced * call is in-flight. * * @template TFn - The wrapped function type. * @template TType - The return type of `TFn` (must be `ObservableInput`). * @template TArgs - The argument tuple. * @param fn - The function to debounce. * @param options - Debounce configuration. * @returns An object with `value$`, `next`, and `idle`. * * @example * ```tsx * const { next: search, value$, idle } = useDebounce( * (query: string) => fetch(`/api/search?q=${query}`).then((r) => r.json()), * { debounce: 300 }, * ); * * useObservableState(value$); // subscribe to results * search('fusion'); // triggers debounced fetch * ``` */ export const useDebounce = (fn, options) => { const [idle, setIdle] = useState(true); const [queuer] = useState(() => options?.queuer ?? new Subject()); const next = useCallback((...args) => queuer.next(args), [queuer]); const debounceFn = useMemo(() => typeof options.debounce === 'function' ? debounce(options.debounce) : debounceTime(options.debounce), [options.debounce]); const value$ = useMemo(() => queuer.pipe(debounceFn, tap(() => setIdle(false)), switchMap((args) => from(fn(...args))), tap(() => setIdle(true))), [queuer, debounceFn, fn]); return { idle, next, value$ }; }; //# sourceMappingURL=useDebounce.js.map