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:
// 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,
};
}// 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.