Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

Pagination and Sorting With searchCriteria

Pagination and Sorting With searchCriteria

~14 Min. Lesezeit Zuletzt aktualisiert am August 8, 2026

Loading 247 products at once would be neither fast nor sensible to display – time to use searchCriteria properly: paging through results and sorting by field.

The key searchCriteria parameters

  • searchCriteria[pageSize] – how many products per page (already used since chapter 7).
  • searchCriteria[currentPage] – which page, starting at 1 (NOT 0!).
  • searchCriteria[sortOrders][0][field] – which field to sort by, e.g. name or price.
  • searchCriteria[sortOrders][0][direction]ASC or DESC.

Extending fetchProducts() with pagination and sorting

src/api/magentoApi.js
const BASE_URL = import.meta.env.VITE_MAGENTO_BASE_URL;
const ACCESS_TOKEN = import.meta.env.VITE_MAGENTO_ACCESS_TOKEN;
const PAGE_SIZE = 12;

async function magentoFetch(path) {
  const response = await fetch(`${BASE_URL}${path}`, {
    headers: {
      Authorization: `Bearer ${ACCESS_TOKEN}`,
    },
  });

  if (!response.ok) {
    throw new Error(`Magento API error: ${response.status}`);
  }

  return response.json();
}

export async function fetchProducts({ page = 1, sortField = 'name', direction = 'ASC' } = {}) {
  const params = new URLSearchParams({
    'searchCriteria[pageSize]': PAGE_SIZE,
    'searchCriteria[currentPage]': page,
    'searchCriteria[sortOrders][0][field]': sortField,
    'searchCriteria[sortOrders][0][direction]': direction,
  });

  const data = await magentoFetch(`/products?${params.toString()}`);
  return {
    products: data.items,
    totalCount: data.total_count,
    pageCount: Math.ceil(data.total_count / PAGE_SIZE),
  };
}

URLSearchParams handles correct URL encoding automatically – considerably less error-prone than manually assembling a string with template literals.

components/Pagination.jsx

src/components/Pagination.jsx
function Pagination({ currentPage, pageCount, onPageChange }) {
  return (
    <div>
      <button
        onClick={() => onPageChange(currentPage - 1)}
        disabled={currentPage <= 1}
      >
        Previous
      </button>
      <span>
        {' '}Page {currentPage} of {pageCount}{' '}
      </span>
      <button
        onClick={() => onPageChange(currentPage + 1)}
        disabled={currentPage >= pageCount}
      >
        Next
      </button>
    </div>
  );
}

export default Pagination;

ProductListPage.jsx: integrating pagination

src/pages/ProductListPage.jsx
import { useEffect, useState } from 'react';
import { fetchProducts } from '../api/magentoApi';
import Pagination from '../components/Pagination';

function ProductListPage() {
  const [products, setProducts] = useState([]);
  const [pageCount, setPageCount] = useState(1);
  const [currentPage, setCurrentPage] = useState(1);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    setLoading(true);
    async function load() {
      const result = await fetchProducts({ page: currentPage });
      setProducts(result.products);
      setPageCount(result.pageCount);
      setLoading(false);
    }
    load();
  }, [currentPage]);

  if (loading) {
    return <p>Loading products...</p>;
  }

  return (
    <div>
      <h1>Products</h1>
      <ul>
        {products.map((product) => (
          <li key={product.sku}>
            {product.name} — {product.price} €
          </li>
        ))}
      </ul>
      <Pagination
        currentPage={currentPage}
        pageCount={pageCount}
        onPageChange={setCurrentPage}
      />
    </div>
  );
}

export default ProductListPage;

[currentPage] as the useEffect dependency ensures a reload happens automatically on page change – EXACTLY the same pattern as [sku] in "React for Beginners" chapter 22.

Tipp: Test it: if your shop has more than 12 products, "Next"/"Previous" should now ACTUALLY load different products – a good moment to check in your Magento admin whether the displayed order matches sortField: 'name'.