83 lines
2.7 KiB
JavaScript
83 lines
2.7 KiB
JavaScript
import { useEffect } from "react"
|
|
import { useQueryClient, useInfiniteQuery } from "@tanstack/react-query"
|
|
import * as api from "../api"
|
|
|
|
const LIMIT = 100
|
|
|
|
/**
|
|
* A wrapper for the React Query library. Constructs the necessary options
|
|
* (including pagination config) to pass into the `useInfiniteQuery` hook.
|
|
*
|
|
* ### Required props
|
|
*
|
|
* @param {Array} key - The key under which the global "query" instance will live.
|
|
* Should be passed as a list of two elements - `[endpoint, { query }]`. The object
|
|
* can also contain additional values (such as `search`) to be used by:
|
|
* 1) React Query, to determine the uniqueness of the query instance
|
|
* 2) the `getRequestParams` function to build the request params.
|
|
*
|
|
* @param {Function} getRequestParams - A function that takes the `key` prop as an
|
|
* argument, and returns `[query, params]` which will be used by `queryFn` that
|
|
* actually calls the API.
|
|
*
|
|
* ### Optional props
|
|
*
|
|
* @param {Function} [afterFetchData] - A function to call after data has been fetched.
|
|
* Receives the API response as an argument.
|
|
*
|
|
* @param {Function} [afterFetchNextPage] - A function to call after the next page has
|
|
* been fetched. Receives the API response as an argument.
|
|
*/
|
|
|
|
export function useAPIClient(props) {
|
|
const {key, getRequestParams, afterFetchData, afterFetchNextPage} = props
|
|
const [endpoint] = key
|
|
const queryClient = useQueryClient()
|
|
|
|
const queryFn = async ({ pageParam, queryKey }) => {
|
|
const [query, params] = getRequestParams(queryKey)
|
|
params.limit = LIMIT
|
|
params.page = pageParam
|
|
|
|
const response = await api.get(endpoint, query, params)
|
|
|
|
if (pageParam === 1 && typeof afterFetchData === 'function') {
|
|
afterFetchData(response)
|
|
}
|
|
|
|
if (pageParam > 1 && typeof afterFetchNextPage === 'function') {
|
|
afterFetchNextPage(response)
|
|
}
|
|
|
|
return response.results
|
|
}
|
|
|
|
// During the cleanup phase, make sure only the first page of results
|
|
// is cached under any `queryKey` containing this endpoint.
|
|
useEffect(() => {
|
|
const key = [endpoint]
|
|
return () => {
|
|
queryClient.setQueriesData(key, (data) => {
|
|
if (data?.pages?.length) {
|
|
return {
|
|
pages: data.pages.slice(0, 1),
|
|
pageParams: data.pageParams.slice(0, 1),
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}, [queryClient, endpoint])
|
|
|
|
const getNextPageParam = (lastPageResults, _, lastPageIndex) => {
|
|
return lastPageResults.length === LIMIT ? lastPageIndex + 1 : null
|
|
}
|
|
const defaultInitialPageParam = 1
|
|
const initialPageParam = props.initialPageParam === undefined ? defaultInitialPageParam : props.initialPageParam
|
|
|
|
return useInfiniteQuery({
|
|
queryKey: key,
|
|
queryFn,
|
|
getNextPageParam,
|
|
initialPageParam
|
|
})
|
|
} |