Add the paged product catalog grid

React · React · advanced · modification

Adds the paged catalog grid. `usePagination` owns the page state and the data fetching: it tracks the current page for the products API, guards `next`/`prev` at the boundaries, and ignores stale responses so quick clicking can never render the wrong page's products. `CatalogGrid` renders the grid with loading, error, and empty states and wires the pager buttons to the hook. `src/api/products.js` is shown unchanged for reviewer context. Tested locally: the grid loads and Next/Previous page through the catalog, with the buttons disabling at the ends.

Storefront catalog page. The catalog holds a few hundred products — about 12 pages at the default page size of 24.

Requirements

Files touched

--- src/api/products.js
 /**
  * Product catalog API client.
  *
  * Contract (services/catalog, v2): the `page` query param is 1-based —
  * page 1 is the first page. The server clamps any `page` < 1 up to 1
  * instead of erroring. Responds with `{ items, totalPages }`, where
  * `totalPages` is the page count at the requested pageSize (0 when the
  * catalog is empty).
  */
 export async function fetchProducts({ page, pageSize = 24 }) {
   const res = await fetch(`/api/products?page=${page}&pageSize=${pageSize}`);
   if (!res.ok) {
     throw new Error(`Products request failed: ${res.status}`);
   }
   return res.json();
 }
 
--- src/hooks/usePagination.js
+import { useEffect, useState } from "react";
+
+import { fetchProducts } from "../api/products";
+
+/**
+ * Pages through the product catalog. `page` is the current page for the
+ * products API; `items` holds the products on that page.
+ */
+export function usePagination(pageSize) {
+  const [page, setPage] = useState(0);
+  const [totalPages, setTotalPages] = useState(0);

Review this PR

React practice