UNPKG

@baaz/adapter

Version:
119 lines (105 loc) 3.63 kB
import { useCallback, useMemo, useState } from 'react'; import { useHistory, useLocation } from 'react-router-dom'; import { getSearchParam } from './useSearchParam'; /** * Sets a query parameter in history. Attempt to use React Router if provided * otherwise fallback to builtins. * * @private */ const setQueryParam = ({ history, location, parameter, value }) => { const { search } = location; const queryParams = new URLSearchParams(search); queryParams.set(parameter, value); if (history.push) { history.push({ search: queryParams.toString() }); } else { // Use the native pushState. See https://developer.mozilla.org/en-US/docs/Web/API/History_API#The_pushState()_method history.pushState('', '', `?${queryParams.toString()}`); } }; const defaultInitialPage = 1; /** * A [React Hook]{@link https://reactjs.org/docs/hooks-intro.html} that provides * pagination logic. * * Use this hook to implement components that need to navigate through paged * data. * * @kind function * * @param {Object} config An object containing configuration values * * @param {String} config.namespace='' The namespace to append to config.parameter in the query. For example: ?namespace_parameter=value * @param {String} config.parameter='page' The name of the query parameter to use for page * @param {Number} config.initialPage The initial current page value * @param {Number} config.intialTotalPages=1 The total pages expected to be usable by this hook * * @return {Object[]} An array with two entries containing the following content: [ {@link PaginationState}, {@link API} ] */ export const usePagination = (props = {}) => { const { namespace = '', parameter = 'page', initialTotalPages = 1 } = props; const searchParam = namespace ? `${namespace}_${parameter}` : parameter; const history = useHistory(); const location = useLocation(); // Fetch the initial page value from location to avoid initializing twice. const initialPage = props.initialPage || parseInt(getSearchParam(searchParam, location) || defaultInitialPage); const [currentPage, setCurrentPage] = useState(initialPage); const [totalPages, setTotalPages] = useState(initialTotalPages); const setPage = useCallback( page => { // Update the query parameter. setQueryParam({ location, history, parameter: searchParam, value: page }); // Update the state object. setCurrentPage(page); }, [history, location, searchParam] ); /** * The current pagination state * * @typedef PaginationState * * @kind Object * * @property {Number} currentPage The current page number * @property {Number} totalPages The total number of pages */ const paginationState = { currentPage, totalPages }; /** * The API object used for modifying the PaginationState. * * @typedef API * * @kind Object */ /** * Set the current page * * @function API.setCurrentPage * * @param {Number} page The number to assign to the current page */ /** * Set the total number of pages * * @function API.setTotalPages * * @param {Number} total The number to set the amount of pages available */ const api = useMemo( () => ({ setCurrentPage: setPage, setTotalPages }), [setPage, setTotalPages] ); return [paginationState, api]; };