import { useEffect, useState, useRef, useCallback } from 'react'; /** * Takes an async function and tracks resolution as a boolean. * * @see https://dataclient.io/docs/api/useLoading * @param func A function returning a promise * @param deps Deps list sent to useCallback() * @example ``` function Button({ onClick, children, ...props }) { const [clickHandler, loading] = useLoading(onClick); return ( ); } ``` */ export default function useLoading Promise>( func: F, deps?: readonly any[], ): [F, boolean, Error | undefined] { const [loading, setLoading] = useState(false); const [error, setError] = useState(undefined); const isMountedRef = useRef(true); useEffect(() => { isMountedRef.current = true; return () => { isMountedRef.current = false; }; }, []); const depsList = deps || [func]; const wrappedFunc = useCallback(async (...args: any) => { setLoading(true); let ret; try { ret = await func(...args); } catch (e: any) { setError(e); } finally { if (isMountedRef.current) { setLoading(false); } } return ret; // eslint-disable-next-line react-hooks/exhaustive-deps }, depsList); return [wrappedFunc as any, loading, error]; }