import * as React from "react"; import useIsMounted from "./useIsMounted"; type RequestResponse = { /** The return value of the request function. */ data: T | undefined; /** The request error, if any. */ error: unknown; /** Whether the request is currently in progress. */ loading: boolean; /** Function to start the request. */ request: () => Promise; }; /** * A hook to make an API request and track its state within a component. * * @param requestFn The function to call to make the request, it should return a promise. * @param makeRequestOnMount Whether to make the request when the component mounts. * @returns An object containing the request state and a function to start the request. */ export default function useRequest( requestFn: () => Promise, makeRequestOnMount = false ): RequestResponse { const isMounted = useIsMounted(); const [data, setData] = React.useState(); const [loading, setLoading] = React.useState(false); const [error, setError] = React.useState(); const request = React.useCallback(async () => { setLoading(true); try { const response = await requestFn(); if (isMounted()) { setData(response); } return response; } catch (err) { if (isMounted()) { setError(err); } } finally { if (isMounted()) { setLoading(false); } } return undefined; }, [requestFn, isMounted]); React.useEffect(() => { if (makeRequestOnMount) { void request(); } }, [request, makeRequestOnMount]); return { data, loading, error, request }; }