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

Pagination in React: Seitennavigation für Listen

Pagination in React

~12 Min. Lesezeit Zuletzt aktualisiert am 8. August 2026

Unsere fetchProducts() lädt bisher immer nur die ersten 20 Produkte. Bei einem Shop mit hunderten Produkten reicht das nicht – wir brauchen "Weiter"/"Zurück"-Navigation durch die Ergebnisse, also Pagination.

magentoApi.js erweitern: eine Seitenzahl akzeptieren

Erweitern Sie fetchProducts() um einen Parameter für die aktuelle Seite. Beide Varianten aus Kapitel 22 unterstützen Pagination, nur die Parameternamen unterscheiden sich:

src/api/magentoApi.js
// Variante A (Magento):
export async function fetchProducts(page = 1, pageSize = 6) {
  const response = await fetch(
    `${BASE_URL}/products?searchCriteria[pageSize]=${pageSize}&searchCriteria[currentPage]=${page}`
  );

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

  const data = await response.json();
  return {
    items: data.items.map(mapMagentoProduct),
    totalCount: data.total_count,
  };
}
src/api/magentoApi.js
// Variante B (dummyjson.com):
export async function fetchProducts(page = 1, pageSize = 6) {
  const skip = (page - 1) * pageSize;
  const response = await fetch(`${BASE_URL}/products?limit=${pageSize}&skip=${skip}`);

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

  const data = await response.json();
  return {
    items: data.products.map(mapMagentoProduct),
    totalCount: data.total,
  };
}

Zwei unterschiedliche API-Philosophien werden hier sichtbar: Magento arbeitet mit "Seitenzahl + Seitengröße" (currentPage/pageSize), dummyjson.com mit "Versatz + Anzahl" (skip/limit – "überspringe die ersten N Einträge"). skip = (page - 1) * pageSize rechnet zwischen den beiden Konzepten um. WICHTIG: fetchProducts() gibt jetzt ein OBJEKT mit items UND totalCount zurück, statt nur eines Arrays – die aufrufende Seite muss das berücksichtigen.

ProductListPage.jsx: Seitennavigation ergänzen

const SEITENGROESSE = 6;

// ... innerhalb der Komponente, State ergänzen:
const [seite, setSeite] = useState(1);
const [gesamtanzahl, setGesamtanzahl] = useState(0);

// ... im useEffect, abhängig von seite:
useEffect(() => {
  async function laden() {
    setLadend(true);
    try {
      const { items, totalCount } = await fetchProducts(seite, SEITENGROESSE);
      setProdukte(items);
      setGesamtanzahl(totalCount);
    } catch (error) {
      setFehler(error.message);
    } finally {
      setLadend(false);
    }
  }
  laden();
}, [seite]);

// ... berechnete Gesamtseitenzahl:
const gesamtseiten = Math.ceil(gesamtanzahl / SEITENGROESSE);

// ... im JSX, nach dem Produkt-Grid:
<div className="pagination">
  <button disabled={seite === 1} onClick={() => setSeite(seite - 1)}>
    Zurück
  </button>
  <span>Seite {seite} von {gesamtseiten}</span>
  <button disabled={seite >= gesamtseiten} onClick={() => setSeite(seite + 1)}>
    Weiter
  </button>
</div>

[seite] als Abhängigkeit im useEffect ist der Schlüssel: Jedes Mal, wenn sich seite durch einen Klick auf "Weiter"/"Zurück" ändert, lädt der Effekt automatisch die passenden Produkte neu. disabled={{seite === 1}} und disabled={{seite >= gesamtseiten}} deaktivieren die Knöpfe an den Rändern, statt eine nicht existierende Seite anzufragen.

Achtung: Ein wichtiger Denkfehler, den Anfänger oft machen: Pagination filtert NICHT das bereits geladene produkte-Array clientseitig, sondern fragt bei JEDEM Seitenwechsel neue Daten vom Server an. Bei kleinen Datenmengen wäre "alles laden, dann clientseitig aufteilen" zwar auch möglich, skaliert aber bei tausenden Produkten nicht – deshalb übernimmt die API selbst die Aufteilung.

Tipp: Unsere Suche (query) filtert weiterhin nur die aktuell geladene Seite, nicht den gesamten Produktkatalog – eine "echte", serverseitige Suche über alle Seiten hinweg würde einen eigenen API-Parameter erfordern (bei Magento z. B. searchCriteria[filterGroups]) und sprengt den Rahmen dieses Einsteiger-Tutorials.