From 48b159002830b1198925bf458dfb2e405298116d Mon Sep 17 00:00:00 2001 From: Muslimjon Date: Wed, 10 Jan 2024 12:38:55 +0100 Subject: [PATCH] create useFetchBatched fook to fetch data with concurrent requests --- packages/utils/src/index.ts | 2 + packages/utils/src/useFetchBatched/index.ts | 1 + .../src/useFetchBatched/useFetchBatched.ts | 30 ++++++++++++ packages/utils/src/usePromiseQueue/index.ts | 1 + .../src/usePromiseQueue/usePromiseQueue.ts | 46 +++++++++++++++++++ 5 files changed, 80 insertions(+) create mode 100644 packages/utils/src/useFetchBatched/index.ts create mode 100644 packages/utils/src/useFetchBatched/useFetchBatched.ts create mode 100644 packages/utils/src/usePromiseQueue/index.ts create mode 100644 packages/utils/src/usePromiseQueue/usePromiseQueue.ts diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 3b023bd8cd..0fe4438129 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -18,3 +18,5 @@ export { useInventory } from './useInventory'; export * from './CypressUtils'; export * from './useInsightsNavigate'; export * from './useExportPDF'; +export * from './usePromiseQueue'; +export * from './useFetchBatched'; diff --git a/packages/utils/src/useFetchBatched/index.ts b/packages/utils/src/useFetchBatched/index.ts new file mode 100644 index 0000000000..da45607b13 --- /dev/null +++ b/packages/utils/src/useFetchBatched/index.ts @@ -0,0 +1 @@ +export { default } from './useFetchBatched'; diff --git a/packages/utils/src/useFetchBatched/useFetchBatched.ts b/packages/utils/src/useFetchBatched/useFetchBatched.ts new file mode 100644 index 0000000000..80d20dd2a7 --- /dev/null +++ b/packages/utils/src/useFetchBatched/useFetchBatched.ts @@ -0,0 +1,30 @@ +import usePromiseQueue from '../usePromiseQueue'; + +type FetchFunctionType = (filter: object | Array, options?: object) => void; + +//hook to enable fetching a lot of data from the API in concurrent API calls +const useFetchBatched = () => { + const { isResolving: isLoading, resolve } = usePromiseQueue(); + + return { + isLoading, + fetchBatched: (fetchFunction: FetchFunctionType, total: number, filter: object, batchSize = 50) => { + const pages = Math.ceil(total / batchSize) || 1; + + const results = resolve([...new Array(pages)].map((_, pageIdx) => () => fetchFunction(filter, { page: pageIdx + 1, per_page: batchSize }))); + + return results; + }, + fetchBatchedInline: (fetchFunction: FetchFunctionType, list: Array, batchSize = 20) => { + const pages = Math.ceil(list.length / batchSize) || 1; + + const results = resolve( + [...new Array(pages)].map((_, pageIdx) => () => fetchFunction(list.slice(batchSize * pageIdx, batchSize * (pageIdx + 1)))) + ); + + return results; + }, + }; +}; + +export default useFetchBatched; diff --git a/packages/utils/src/usePromiseQueue/index.ts b/packages/utils/src/usePromiseQueue/index.ts new file mode 100644 index 0000000000..56a903a2c5 --- /dev/null +++ b/packages/utils/src/usePromiseQueue/index.ts @@ -0,0 +1 @@ +export { default } from './usePromiseQueue'; diff --git a/packages/utils/src/usePromiseQueue/usePromiseQueue.ts b/packages/utils/src/usePromiseQueue/usePromiseQueue.ts new file mode 100644 index 0000000000..2474f49ee1 --- /dev/null +++ b/packages/utils/src/usePromiseQueue/usePromiseQueue.ts @@ -0,0 +1,46 @@ +import { useCallback, useState } from 'react'; +import pAll from 'p-all'; + +const DEFAULT_CONCURRENT_PROMISES = 2; + +type PromiseQueueStateType = { + isResolving: boolean; + //undeterministic result type by p-all package + promiseResults: any; +}; + +// hook that provides queued promises with state +const usePromiseQueue = (concurrency = DEFAULT_CONCURRENT_PROMISES) => { + const defaultState: PromiseQueueStateType = { + isResolving: false, + promiseResults: undefined, + }; + const [results, setResults] = useState(defaultState); + + const resolve = useCallback( + async (fns: any) => { + setResults((state) => ({ + ...state, + isResolving: true, + })); + const results: any = await pAll(fns, { + concurrency, + }); + setResults({ + isResolving: false, + promiseResults: results, + }); + + return results; + }, + [concurrency] + ); + + return { + isResolving: results.isResolving, + results: results.promiseResults, + resolve, + }; +}; + +export default usePromiseQueue;