import { AxiosInstance } from 'axios' import { useRef, useState } from 'react' import { uniqBy } from 'lodash' export type NextPage = () => Promise export interface PaginationData { page: number itemsPerPage: number totalItems: number hasMore: boolean rows: T[] } interface UsePaginationOptions { api: AxiosInstance url: string defaultPaginationData?: PaginationData inverse?: boolean } export type SetData = React.Dispatch>> interface UsePaginationReturn { data: PaginationData nextPage: NextPage setData: SetData isLoading: boolean } const defaultData: PaginationData = { page: 0, itemsPerPage: 20, totalItems: 0, hasMore: true, rows: [] } export const usePagination = ( options: UsePaginationOptions ): UsePaginationReturn => { const { api, url, defaultPaginationData = defaultData, inverse = false } = options const page = useRef(defaultPaginationData.page + 1) const [data, setData] = useState>(defaultPaginationData) const [isLoading, setIsLoading] = useState(false) const nextPage: NextPage = async () => { if (isLoading) { return } setIsLoading(true) const { data: newData } = await api.get>( `${url}?itemsPerPage=${defaultPaginationData.itemsPerPage}&page=${page.current}` ) const rows = inverse ? [...newData.rows, ...data.rows] : [...data.rows, ...newData.rows] setData({ page: page.current, itemsPerPage: defaultPaginationData.itemsPerPage, hasMore: newData.hasMore, totalItems: newData.totalItems, rows: uniqBy(rows, 'id') }) setIsLoading(false) page.current += 1 } return { data, setData, nextPage, isLoading } }