Rev 3533 | Rev 3603 | Ir a la última revisión | Autoría | Comparar con el anterior | Ultima modificación | Ver Log |
import { useEffect, useState, useCallback, useMemo } from 'react';
import { useFetch } from './useFetch';
export function usePagination(
url,
{
initialPage = 1,
initialLimit = 10,
initialParams = {},
enableInfiniteScroll = false,
resetOnUrlChange = true
} = {}
) {
const [items, setItems] = useState([]);
const [page, setPage] = useState(initialPage);
const [totalPages, setTotalPages] = useState(0);
const [totalItems, setTotalItems] = useState(0);
const [limit, setLimit] = useState(initialLimit);
const [params, setParams] = useState({ page, limit, ...initialParams });
const { data, loading, error, refetch } = useFetch(url, {
params
});
// Memoized pagination state
const paginationState = useMemo(
() => ({
page,
limit,
totalPages,
totalItems,
hasMore: page < totalPages,
hasPrevious: page > 1,
isFirstPage: page === 1,
isLastPage: page === totalPages
}),
[page, limit, totalPages, totalItems]
);
// Optimized page navigation functions
const nextPage = useCallback(() => {
if (paginationState.hasMore) {
setPage((prevPage) => prevPage + 1);
}
}, [paginationState.hasMore]);
const prevPage = useCallback(() => {
if (paginationState.hasPrevious) {
setPage((prevPage) => prevPage - 1);
}
}, [paginationState.hasPrevious]);
const goToPage = useCallback(
(newPage) => {
if (newPage >= 1 && newPage <= totalPages) {
setPage(newPage);
}
},
[totalPages]
);
const setPageLimit = useCallback((newLimit) => {
if (newLimit > 0) {
setLimit(newLimit);
setPage(1);
}
}, []);
const resetPagination = useCallback(() => {
setPage(initialPage);
setItems([]);
setTotalPages(0);
setTotalItems(0);
}, [initialPage]);
const updateParams = useCallback((newParams) => {
setParams((prevParams) => ({ ...prevParams, ...newParams }));
}, []);
// Handle data updates with flexible structure support
useEffect(() => {
if (data) {
let newItems = [];
let pages = 0;
let items = 0;
// Handle different response structures
if (data?.current?.items) {
// Structure: { current: { items: [] }, total: { pages: number, items: number } }
newItems = data.current.items;
pages = data.total?.pages || 0;
items = data.total?.items || 0;
} else if (data?.data && Array.isArray(data.data)) {
// Structure: { data: [], pagination: { ... } }
newItems = data.data;
pages = data.pagination?.pageCount || data.pagination?.last || 0;
items = data.pagination?.totalItemCount || 0;
} else if (Array.isArray(data)) {
// Structure: direct array
newItems = data;
pages = 1;
items = data.length;
} else if (data?.items && Array.isArray(data.items)) {
// Structure: { items: [], pagination: { ... } }
newItems = data.items;
pages = data.pagination?.pageCount || data.pagination?.last || 0;
items = data.pagination?.totalItemCount || 0;
}
setItems((prevItems) => {
if (enableInfiniteScroll && page > 1) {
// For infinite scroll, append new items
return [...prevItems, ...newItems];
} else {
// For regular pagination, replace items
return newItems;
}
});
setTotalPages(pages);
setTotalItems(items);
}
}, [data, page, enableInfiniteScroll]);
// Update params when page or limit changes
useEffect(() => {
setParams((prevParams) => ({
...prevParams,
page,
limit
}));
}, [page, limit]);
// Reset pagination when URL changes (if enabled)
useEffect(() => {
if (resetOnUrlChange) {
resetPagination();
}
}, [url, resetOnUrlChange, resetPagination]);
return {
// Data
items,
...paginationState,
// Loading and error states
loading,
error,
// Actions
nextPage,
prevPage,
goToPage,
setPageLimit,
resetPagination,
updateParams,
refetch
};
}