react-use-pagination
Version:
A React hook to help manage pagination state
138 lines (133 loc) • 4.16 kB
JavaScript
// src/getPaginationMeta.ts
var getPreviousEnabled = (currentPage) => currentPage > 0;
var getNextEnabled = (currentPage, totalPages) => currentPage + 1 < totalPages;
var getTotalPages = (totalItems, pageSize) => Math.ceil(totalItems / pageSize);
var getStartIndex = (pageSize, currentPage) => pageSize * currentPage;
var getEndIndex = (pageSize, currentPage, totalItems) => {
const lastPageEndIndex = pageSize * (currentPage + 1);
if (lastPageEndIndex > totalItems) {
return totalItems - 1;
}
return lastPageEndIndex - 1;
};
var limitPageBounds = (totalItems, pageSize) => (page) => Math.min(Math.max(page, 0), getTotalPages(totalItems, pageSize) - 1);
var getPaginationMeta = ({
totalItems,
pageSize,
currentPage
}) => {
const totalPages = getTotalPages(totalItems, pageSize);
return {
totalPages,
startIndex: getStartIndex(pageSize, currentPage),
endIndex: getEndIndex(pageSize, currentPage, totalItems),
previousEnabled: getPreviousEnabled(currentPage),
nextEnabled: getNextEnabled(currentPage, totalPages)
};
};
// src/usePagination.ts
import { useCallback, useEffect, useMemo, useRef, useReducer } from "react";
// src/paginationStateReducer.ts
var getCurrentPageReducer = (rootState) => function currentPageReducer(state, action) {
switch (action.type) {
case "SET_PAGE":
return limitPageBounds(rootState.totalItems, rootState.pageSize)(action.page);
case "NEXT_PAGE":
return limitPageBounds(rootState.totalItems, rootState.pageSize)(state + 1);
case "PREVIOUS_PAGE":
return limitPageBounds(rootState.totalItems, rootState.pageSize)(state - 1);
case "SET_PAGESIZE":
return limitPageBounds(rootState.totalItems, action.pageSize)(action.nextPage ?? state);
case "SET_TOTALITEMS":
return limitPageBounds(action.totalItems, rootState.pageSize)(action.nextPage ?? state);
default:
return state;
}
};
function totalItemsReducer(state, action) {
switch (action.type) {
case "SET_TOTALITEMS":
return action.totalItems;
default:
return state;
}
}
function pageSizeReducer(state, action) {
switch (action.type) {
case "SET_PAGESIZE":
return action.pageSize;
default:
return state;
}
}
function paginationStateReducer(state, action) {
return {
currentPage: getCurrentPageReducer(state)(state.currentPage, action),
totalItems: totalItemsReducer(state.totalItems, action),
pageSize: pageSizeReducer(state.pageSize, action)
};
}
// src/usePagination.ts
function usePagination({
totalItems = 0,
initialPage = 0,
initialPageSize = 0
} = {}) {
const initialState = {
totalItems,
pageSize: initialPageSize,
currentPage: initialPage
};
const [paginationState, dispatch] = useReducer(paginationStateReducer, initialState);
const totalItemsRef = useRef(totalItems);
totalItemsRef.current = totalItems;
useEffect(() => {
return () => {
if (typeof totalItemsRef.current !== "number" || totalItems === totalItemsRef.current) {
return;
}
dispatch({ type: "SET_TOTALITEMS", totalItems: totalItemsRef.current });
};
}, [totalItems]);
return {
...paginationState,
...useMemo(() => getPaginationMeta(paginationState), [paginationState]),
setPage: useCallback((page) => {
dispatch({
type: "SET_PAGE",
page
});
}, []),
setNextPage: useCallback(() => {
dispatch({ type: "NEXT_PAGE" });
}, []),
setPreviousPage: useCallback(() => {
dispatch({ type: "PREVIOUS_PAGE" });
}, []),
setPageSize: useCallback((pageSize, nextPage = 0) => {
dispatch({ type: "SET_PAGESIZE", pageSize, nextPage });
}, [])
};
}
// src/Pagination.tsx
function Pagination({
children,
totalItems = 0,
initialPage = 0,
initialPageSize
}) {
return children(usePagination({ totalItems, initialPage, initialPageSize }));
}
Pagination.displayName = "Pagination";
export {
Pagination,
getEndIndex,
getNextEnabled,
getPaginationMeta,
getPreviousEnabled,
getStartIndex,
getTotalPages,
limitPageBounds,
usePagination
};
//# sourceMappingURL=react-use-pagination.mjs.map