vitess.io/vitess@v0.16.2/web/vtadmin/src/hooks/useURLPagination.ts (about) 1 /** 2 * Copyright 2021 The Vitess Authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 import { useEffect } from 'react'; 17 18 import { useHistory, useLocation } from 'react-router-dom'; 19 import { useURLQuery } from './useURLQuery'; 20 21 export interface PaginationOpts { 22 totalPages: number; 23 } 24 25 export interface PaginationParams { 26 page: number; 27 } 28 29 // This assumes we always want to 1-index our pages, where "page 1" is the first page. 30 // If we find a need for zero-indexed pagination, we can make this configurable. 31 const FIRST_PAGE = 1; 32 33 /** 34 * useURLPagination is a hook for components that: 35 * - use pagination in some way 36 * - encode pagination state in the URL (e.g., /some/route?page=123) 37 */ 38 export const useURLPagination = ({ totalPages }: PaginationOpts): PaginationParams => { 39 const history = useHistory(); 40 const location = useLocation(); 41 const { query, replaceQuery } = useURLQuery({ parseNumbers: true }); 42 43 // A slight nuance here -- if `page` is not in the URL at all, then we can assume 44 // it's the first page. This makes for slightly nicer URLs for the first/default page: 45 // "/foo" instead of "/foo?page=1". No redirect required. 46 const page = !('page' in query) || query.page === null ? FIRST_PAGE : query.page; 47 48 useEffect(() => { 49 // If the value in the URL *is* defined but is negative, non-numeric, 50 // too big, or otherwise Weird, then we *do* want to redirect to the first page. 51 const isPageTooBig = typeof page === 'number' && totalPages > 0 && page > totalPages; 52 const isPageTooSmall = typeof page === 'number' && page < FIRST_PAGE; 53 54 if (isPageTooBig || isPageTooSmall || typeof page !== 'number') { 55 // Replace history so the invalid value is not persisted in browser history 56 replaceQuery({ page: FIRST_PAGE }); 57 } 58 }, [page, totalPages, history, location.pathname, query, replaceQuery]); 59 60 return { 61 page, 62 } as PaginationParams; 63 };