Server-Side Search With searchCriteria Filters
Server-Side Search With searchCriteria Filters
~13 Min. Lesezeit Zuletzt aktualisiert am August 8, 2026
EXACTLY the same server-side search logic as the React web tutorial – here combined with a TextInput and FlatList's ListHeaderComponent prop, so the search bar scrolls WITH the list.
Extending fetchProducts() with a search option
// ... previous code ...
export async function fetchProducts({
page = 1,
sortField = 'name',
direction = 'ASC',
query = '',
} = {}) {
const params = new URLSearchParams({
'searchCriteria[pageSize]': PAGE_SIZE,
'searchCriteria[currentPage]': page,
'searchCriteria[sortOrders][0][field]': sortField,
'searchCriteria[sortOrders][0][direction]': direction,
});
if (query.trim() !== '') {
params.set('searchCriteria[filterGroups][0][filters][0][field]', 'name');
params.set('searchCriteria[filterGroups][0][filters][0][value]', `%${query}%`);
params.set('searchCriteria[filterGroups][0][filters][0][condition_type]', 'like');
}
const data = await magentoFetch(`/products?${params.toString()}`);
return {
products: data.items,
totalCount: data.total_count,
pageCount: Math.ceil(data.total_count / PAGE_SIZE),
};
}components/SearchBar.js
import { useState } from 'react';
import { TextInput, Button, View, StyleSheet } from 'react-native';
export default function SearchBar({ onSearch }) {
const [input, setInput] = useState('');
return (
<View style={styles.row}>
<TextInput
style={styles.input}
placeholder="Search products..."
value={input}
onChangeText={setInput}
onSubmitEditing={() => onSearch(input)}
returnKeyType="search"
/>
<Button title="Search" onPress={() => onSearch(input)} />
</View>
);
}
const styles = StyleSheet.create({
row: { flexDirection: 'row', alignItems: 'center', padding: 16, gap: 8 },
input: { flex: 1, borderWidth: 1, borderColor: '#ccc', borderRadius: 6, padding: 8 },
});onSubmitEditing additionally triggers the search when the "search" key is pressed on the on-screen keyboard – a mobile interaction pattern solved differently in the React web tutorial (via <form onSubmit>).
ProductListScreen.js: integrating search
import { useEffect, useState } from 'react';
import { FlatList, ActivityIndicator, StyleSheet } from 'react-native';
import { fetchProducts } from '../api/magentoApi';
import ProductCard from '../components/ProductCard';
import SearchBar from '../components/SearchBar';
export default function ProductListScreen() {
const [products, setProducts] = useState([]);
const [page, setPage] = useState(1);
const [pageCount, setPageCount] = useState(1);
const [query, setQuery] = useState('');
const [loading, setLoading] = useState(true);
const [loadingMore, setLoadingMore] = useState(false);
useEffect(() => {
setLoading(true);
async function searchAndLoad() {
const result = await fetchProducts({ page: 1, query });
setProducts(result.products);
setPageCount(result.pageCount);
setPage(1);
setLoading(false);
}
searchAndLoad();
}, [query]);
async function loadNextPage() {
if (loadingMore || page >= pageCount) {
return;
}
setLoadingMore(true);
const nextPage = page + 1;
const result = await fetchProducts({ page: nextPage, query });
setProducts((previous) => [...previous, ...result.products]);
setPage(nextPage);
setLoadingMore(false);
}
return (
<FlatList
data={products}
keyExtractor={(product) => product.sku}
renderItem={({ item }) => <ProductCard product={item} />}
ListHeaderComponent={<SearchBar onSearch={setQuery} />}
ListEmptyComponent={
loading ? <ActivityIndicator size="large" /> : null
}
onEndReached={loadNextPage}
onEndReachedThreshold={0.5}
ListFooterComponent={loadingMore ? <ActivityIndicator /> : null}
/>
);
}
const styles = StyleSheet.create({});ListHeaderComponent renders SearchBar as PART of the list – it scrolls along, instead of being pinned to the top of the screen. [query] as the useEffect dependency automatically reloads from page 1 whenever the search term changes – setPage(1) prevents the same subtle bug as in the React web tutorial.
Tipp: Search for a word fragment you'd expect in SEVERAL of your real product names – if only matching results show up, AND loading more works correctly within the filtered results, server-side search is working as intended.