ReactJS paginated component with React Router I've recently started journey with ReactJS and to begin with I wanted to try something a bit more complex - paginated list of elements with back functionality enabled.
Below are two main components that I'd like to get feedback about. Especially PagedListings.
import './App.css';
import PagedListings from './components/PagedListings';
import ScrollToTop from './components/ScrollToTop';
import React from &quot;react&quot;;
import { Route } from 'react-router';
import { BrowserRouter as Router } from 'react-router-dom';

function App() {
  return (
    &lt;Router&gt;
    &lt;ScrollToTop&gt;
       &lt;Route path={[&quot;/&quot;, &quot;/:page&quot;]} component={PagedListings}/&gt;
    &lt;/ScrollToTop&gt;
    &lt;/Router&gt;
  );
}

export default App;

And the actual component executing planned task
import React, { useMemo } from &quot;react&quot;;
import ListingsContainer from &quot;./ListingsContainer&quot;;
import Pagination from &quot;@material-ui/lab/Pagination&quot;;
import { useHistory, useLocation } from &quot;react-router-dom&quot;;

const LISTINGS = [&quot;Rec1&quot;, &quot;Rec2&quot;, &quot;Rec3&quot;,
  &quot;Rec4&quot;, &quot;Rec5&quot;, &quot;Rec6&quot;, &quot;Rec7&quot;, &quot;Rec8&quot;,
  &quot;Rec9&quot;, &quot;Rec10&quot;,];
const DEFAULT_PAGE = 1;
const MAX_PAGE_COUNT = 10;

function PagedListings(props) {
  const history = useHistory();
  const location = useLocation();
  const urlParams = useMemo(() =&gt; {
    return new URLSearchParams(location.search);
  }, [location.search]);

  const handleChange = (
    event: React.MouseEvent&lt;HTMLButtonElement&gt; | null,
    newPage: number
  ) =&gt; {
    let oneBasedNewPage = newPage;

    urlParams.set(&quot;page&quot;, oneBasedNewPage.toString());
    updateURL();
  };

  const updateURL = () =&gt; {
    history.push({
      pathname: location.pathname,
      search: `?${urlParams}`,
    });
  };

  function getPageNumber() {
    let newPage = parseInt(urlParams.get(&quot;page&quot;)) || DEFAULT_PAGE;
    return newPage &lt;= MAX_PAGE_COUNT ? newPage : MAX_PAGE_COUNT;
  }

  return (
    &lt;&gt;
      &lt;ListingsContainer listings={LISTINGS.slice(0, getPageNumber())} /&gt;
      &lt;Pagination
        count={MAX_PAGE_COUNT}
        defaultPage={DEFAULT_PAGE}
        page={getPageNumber()}
        onChange={handleChange}
      /&gt;
    &lt;/&gt;
  );
}

export default PagedListings;
Your code looks quite reasonable. There are only a few small things I notice:

Indent the JSX in App a bit more: ScrollToTop is a child of Router, so it should be indented further, not on the same level as Router. (It doesn't really make a difference here, but it's good to be consistent, and could be an improvement if that section ever got more complicated)

Avoid let, prefer const - ESLint rule here.

Or, in the case of oneBasedNewPage, consider defining the argument with that name instead of creating a new variable - and maybe call it oneIndexed, not oneBased:
const handleChange = (
  event: React.MouseEvent&lt;HTMLButtonElement&gt; | null,
  oneIndexedNewPage: number
) =&gt; {


URLSearchParams does not differentiate between numbers and strings.
urlParams.set(&quot;page&quot;, oneBasedNewPage.toString());

can be
urlParams.set(&quot;page&quot;, oneIndexedNewPage);

if you wish.

Consider if using Math.min might be clearer than the conditional operator:
function getPageNumber() {
  const newPage = parseInt(urlParams.get(&quot;page&quot;)) || DEFAULT_PAGE;
  return Math.min(newPage, MAX_PAGE_COUNT);
}