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

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

api/magentoApi.js
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.

screens/ProductListScreen.js
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.