I am building pagination for React project. The pagination itself does work when I click on prev or next page buttons, but I've got 2 problems, which I can't figure out.
I also get this warning in chrome dev tools:
Use of history.pushState in a trivial session history context, which maintains only one session history entry.
It seems like this warning indicated the problem, but how to save multiple history records?
"http://localhost:5173/?p=1"
let's say to "http://localhost:5173/?p=3"
nothing happens. I see that the page refreshes and I believe my new "?p=3"
query is not persisted somehow so useEffect
code does not run?Code:
let [currentPage, setCurrentPage] = useState(getCurrentPage());
let [pagesCount, setPagesCount] = useState(0);
let [itemsCount, setItemsCount] = useState(0);
let [productData, UpdateProductData] = useState([]);
const [searchParams, setSearchParams] = useSearchParams();
// On init
useEffect(() => {
getCurrentPage();
setSearchParams({ p: `${currentPage}` });
calcPagesCount();
getData();
}, []);
// Updates screen if query is changed by browser back button or manually changing query in url bar
useEffect(() => {
let CurrentPageFromQuery: number;
CurrentPageFromQuery = Number(location.search.replace(/\D/g, ""));
setCurrentPage(CurrentPageFromQuery);
saveCurrentPage();
getData();
}, [searchParams]);
// Updates query if next/prev page buttons are clicked
useEffect(() => {
saveCurrentPage();
getData();
setSearchParams({ p: `${currentPage}` });
}, [currentPage]);
function prevPage() {
if (currentPage !== 1) {
getCurrentPage();
setCurrentPage(currentPage - 1);
saveCurrentPage();
}
}
function nextPage() {
if (currentPage !== pagesCount) {
getCurrentPage();
setCurrentPage(currentPage + 1);
saveCurrentPage();
}
}
function saveCurrentPage() {
sessionStorage.setItem("current page", String(currentPage));
}
function getCurrentPage(): number {
return Number(sessionStorage.getItem("current page") || 1);
}
async function calcPagesCount() {
const api_url = `https://******&per_page=99`;
const req = await fetch(api_url);
const products = await req.json();
setItemsCount(products.length);
setPagesCount(Math.floor(products.length / 9));
}
async function getData() {
const api_url = `https://******&per_page=9&page=${currentPage}`;
const req = await fetch(api_url);
const products = await req.json();
UpdateProductData(products);
}
You should have only a single source of truth for what page you are on. Here you are using the URL search params, and a local currentPage
state, and then sessionStorage on top of that. I think you also have too many side-effects and overloaded functions/handlers/callbacks.
I suspect you don't need the currentPage
state, you can read and update the p
URLSearchParameter and synchronize to/from sessionStorage.
Suggested Changes:
p
search parameter from sessionStorage if p
is not set and there is a stored session value.prevPage
/nextPage
only update the URL search paramsExample:
const [searchParams, setSearchParams] = useSearchParams();
const [pagesCount, setPagesCount] = useState(0);
const [itemsCount, setItemsCount] = useState(0);
const [productData, UpdateProductData] = useState([]);
// Read current page from search params, fallback to storage
const currentPage = Number(searchParams.get("p")) ?? getCurrentPage();
// Fetch data for the current page
useEffect(() => {
getData(currentPage);
calcPagesCount();
saveCurrentPage(currentPage);
}, [currentPage]);
function prevPage() {
setSearchParams(searchParams => {
const p = Number(searchParams.get("p")) || 1;
searchParams.set("p", Math.max(1, p - 1));
return searchParams;
});
}
function nextPage() {
setSearchParams(searchParams => {
const p = Number(searchParams.get("p")) || 1;
searchParams.set("p", Math.min(p + 1, pagesCount));
return searchParams;
});
}
function saveCurrentPage(currentPage: number) {
sessionStorage.setItem("current page", String(currentPage));
}
function getCurrentPage(): number {
return Number(sessionStorage.getItem("current page") || 1);
}
async function getData(currentPage: number) {
const api_url = `https://******&per_page=9&page=${currentPage}`;
const req = await fetch(api_url);
const products = await req.json();
UpdateProductData(products);
}