Pagination and Sorting With searchCriteria
Pagination and Sorting With searchCriteria
~14 Min. Lesezeit Zuletzt aktualisiert am August 8, 2026
EXACTLY as in the React web tutorial, we use searchCriteria for pagination and sorting – in React Native, we additionally combine it with FlatList's built-in "load more on scroll" instead of buttons.
Extending fetchProducts() with pagination and sorting
const BASE_URL = process.env.EXPO_PUBLIC_MAGENTO_BASE_URL;
const ACCESS_TOKEN = process.env.EXPO_PUBLIC_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),
};
}Loading more on scroll: onEndReached
Instead of "Next"/"Previous" buttons like the React web tutorial, here we use the pattern more typical for mobile lists: automatically loading the next page once the user scrolls near the end of the list.
import { useEffect, useState } from 'react';
import { FlatList, Text, View, ActivityIndicator, StyleSheet } from 'react-native';
import { fetchProducts } from '../api/magentoApi';
export default function ProductListScreen() {
const [products, setProducts] = useState([]);
const [page, setPage] = useState(1);
const [pageCount, setPageCount] = useState(1);
const [loading, setLoading] = useState(true);
const [loadingMore, setLoadingMore] = useState(false);
useEffect(() => {
async function loadFirstPage() {
const result = await fetchProducts({ page: 1 });
setProducts(result.products);
setPageCount(result.pageCount);
setPage(1);
setLoading(false);
}
loadFirstPage();
}, []);
async function loadNextPage() {
if (loadingMore || page >= pageCount) {
return; // already loading, or already on the last page
}
setLoadingMore(true);
const nextPage = page + 1;
const result = await fetchProducts({ page: nextPage });
setProducts((previous) => [...previous, ...result.products]);
setPage(nextPage);
setLoadingMore(false);
}
if (loading) {
return <ActivityIndicator style={styles.centered} size="large" />;
}
return (
<FlatList
data={products}
keyExtractor={(product) => product.sku}
renderItem={({ item }) => (
<View style={styles.row}>
<Text style={styles.name}>{item.name}</Text>
<Text>{item.price} €</Text>
</View>
)}
onEndReached={loadNextPage}
onEndReachedThreshold={0.5}
ListFooterComponent={loadingMore ? <ActivityIndicator /> : null}
/>
);
}
const styles = StyleSheet.create({
centered: { flex: 1, justifyContent: 'center' },
row: { padding: 16, borderBottomWidth: 1, borderBottomColor: '#eee' },
name: { fontWeight: 'bold', marginBottom: 4 },
});onEndReachedThreshold={0.5} triggers onEndReached once 50% of the list's height remains until the actual end – so loading starts BEFORE the user really reaches the end, which feels smoother.
Achtung: The loadingMore guard in loadNextPage() is IMPORTANT: FlatList can trigger onEndReached MULTIPLE times in quick succession under some circumstances (e.g. fast scrolling) – without this guard, several parallel requests for the same page would fire and insert duplicates into the list.