{"version":3,"file":"index.cjs","names":[],"sources":["../../../src/hooks/useBlockMultipleAsyncCalls/index.ts"],"sourcesContent":["import { createSingleRequest } from '@modern-kit/utils';\nimport { useCallback, useRef, useState } from 'react';\n\ninterface UseBlockMultipleAsyncCallsReturnType {\n  isError: boolean;\n  isLoading: boolean;\n  blockMultipleAsyncCalls: <T, Args extends unknown[]>(\n    callback: (...args: Args) => Promise<T>,\n  ) => (...args: Args) => Promise<T | undefined>;\n}\n\n/**\n * @description `useBlockMultipleAsyncCalls` 훅은 진행 중인 비동기 호출이 있을 때 중복 호출을 방지하기 위한 커스텀 훅입니다.\n *\n * `debounce/throttle`는 함수의 중복 호출을 방지하는 데 대부분의 경우에 효과적입니다.\n * 하지만, `debounce/throttle`는 비동기 작업의 완료를 보장하지 않기 때문에 다음과 같은 한계가 있습니다:\n *\n * 1. `debounce/throttle` 시간이 API 응답 시간보다 짧을 경우: 비동기 작업이 완료되지 않은 상태에서 `다시 호출`될 수 있습니다.\n * 2. `debounce/throttle` 시간이 API 응답 시간보다 길 경우: 비동기 작업이 완료되었지만 `버튼`과 같은 요소가 여전히 `비활성화`되어 있을 수 있습니다.\n * 3. `즉각적인 반응`을 원하는 경우: `debounce/throttle`는 호출을 지연시키기 때문에 사용자에게 `즉각적인 반응`을 보여주기에 제한적입니다.\n * 4. `debounce/throttle`은 `시간`을 기반으로 동작하기 때문에 `얼마나 자주 실행`되는지가 중요하지 `중복 호출 여부`를 파악하기 어렵습니다.\n *\n * 대부분의 경우에 `debounce`만으로 충분하지만, 위와 같은 한계점을 대응하고자 한다면 `useBlockMultipleAsyncCalls`를 사용할 수 있습니다.\n *\n * @returns {UseBlockMultipleAsyncCallsReturnType} 다음을 포함하는 객체:\n * - `isError`: 비동기 작업 중 에러가 발생했는지 나타내는 불리언 값\n * - `isLoading`: 현재 비동기 작업이 진행 중인지 나타내는 불리언 값\n * - `blockMultipleAsyncCalls`: 비동기 작업을 래핑하여 중복 호출을 방지하는 함수\n *\n * @example\n * ```tsx\n * const Example = () => {\n *   const { isError, isLoading, blockMultipleAsyncCalls } = useBlockMultipleAsyncCalls();\n *\n *   const fetchApi = async () => {\n *     const data = await fetchData();\n *     // 데이터 처리\n *   };\n *   const handleClick = blockMultipleAsyncCalls(fetchApi);\n *\n *   return (\n *     <div>\n *       <button onClick={handleClick} disabled={isLoading}>데이터 불러오기</button>\n *       {isError && <p>에러 발생</p>}\n *     </div>\n *   );\n * }\n * ```\n */\nexport function useBlockMultipleAsyncCalls(): UseBlockMultipleAsyncCallsReturnType {\n  const [isLoading, setIsLoading] = useState(false);\n  const [isError, setIsError] = useState(false);\n\n  const singleRequestRef = useRef(createSingleRequest());\n\n  const blockMultipleAsyncCalls = useCallback(\n    <T, Args extends unknown[]>(callback: (...args: Args) => Promise<T>) => {\n      return singleRequestRef.current(async (...args: Args) => {\n        setIsLoading(true);\n        setIsError(false);\n        try {\n          return await callback(...args);\n        } catch (error) {\n          setIsError(true);\n          throw error;\n        } finally {\n          setIsLoading(false);\n        }\n      });\n    },\n    [],\n  );\n\n  return {\n    isError,\n    isLoading,\n    blockMultipleAsyncCalls,\n  };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiDA,SAAgB,6BAAmE;CACjF,MAAM,CAAC,WAAW,iBAAA,GAAA,MAAA,UAAyB,MAAM;CACjD,MAAM,CAAC,SAAS,eAAA,GAAA,MAAA,UAAuB,MAAM;CAE7C,MAAM,oBAAA,GAAA,MAAA,SAAA,GAAA,kBAAA,sBAA+C,CAAC;CAoBtD,OAAO;EACL;EACA;EACA,0BAAA,GAAA,MAAA,cApB4B,aAA4C;GACtE,OAAO,iBAAiB,QAAQ,OAAO,GAAG,SAAe;IACvD,aAAa,KAAK;IAClB,WAAW,MAAM;IACjB,IAAI;KACF,OAAO,MAAM,SAAS,GAAG,KAAK;aACvB,OAAO;KACd,WAAW,KAAK;KAChB,MAAM;cACE;KACR,aAAa,MAAM;;KAErB;KAEJ,EAAE,CAMqB;EACxB"}