import axios, { Canceler, AxiosInstance, AxiosResponse } from 'axios'; import { useCallback, useEffect, useRef, useState } from 'react'; type Options = { sendRequest: (axiosInstance: AxiosInstance, query: Query) => Promise>; onError?: (err: Error) => void; }; export function useRequestCallback({ onError, sendRequest, }: Options): [(query: Query) => void, Response | null, boolean] { const [response, setResponse] = useState(null); const [loading, setLoading] = useState(false); const cancel = useRef<() => void>(); useEffect(() => (): void => cancel.current?.(), []); const onRequest = useCallback( (query: Query) => { let cancelled = false; let cancelRequest: Canceler | null = null; cancel.current?.(); cancel.current = (): void => { cancelled = true; cancelRequest?.(); }; const axiosWithToken = axios.create({ cancelToken: new axios.CancelToken((token): void => { cancelRequest = token; }), }); const makeRequest = async (): Promise => { try { setLoading(true); const res = await sendRequest(axiosWithToken, query); if (!cancelled) { setResponse(res.data); } } catch (err) { if (!axios.isCancel(err)) { onError?.(err); } } finally { if (!cancelled) { setLoading(false); } } }; makeRequest(); }, [onError, sendRequest], ); return [onRequest, response, loading]; }