When you're building a dynamic frontend—like a game store, product listing, or job board—your UI needs to handle a lot of state:
- What page are we on?
- What filters are selected?
- Are we sorting by newest, most relevant, or trending?
- What platform, genre, or tags are selected?
Managing all of that with separate useState
hooks or deeply nested props can quickly become a nightmare. Enter the Query Object Pattern.
🎯 What Is a Query Object?
A Query Object is a single JavaScript object that encapsulates all your query parameters—filter values, sort order, pagination, etc.
const [query, setQuery] = useState({
genreId: null,
platformId: null,
sortOrder: 'relevance',
searchText: '',
page: 1,
});
Instead of spreading your state across multiple hooks:
const [genreId, setGenreId] = useState(null);
const [platformId, setPlatformId] = useState(null);
...
You just manage one query
object. It's simpler, cleaner, and scales well.
🚀 How It Works in Practice
Let’s say you have a dropdown to select a platform (PC, PlayStation, etc.). Instead of setting platformId
directly, you update the query object:
<Button onClick={() => setQuery({ ...query, platformId: 2 })}>
Select PC
</Button>
When your user types into a search bar:
<input
type="text"
value={query.searchText}
onChange={(e) => setQuery({ ...query, searchText: e.target.value })}
/>
You now have a centralized source of truth for all the UI state.
🔄 Making API Calls with the Query Object
Using the useEffect
hook, you can react to query changes and trigger API requests:
useEffect(() => {
fetchGames(query);
}, [query]);
Now whenever any filter, sort option, or pagination value changes, the query
object changes—and so does the data.
🌟 TypeScript Makes It Even Better
With TypeScript, you can define a type for your query object:
type GameQuery = {
genreId: number | null;
platformId: number | null;
sortOrder: string;
searchText: string;
page: number;
};
This gives you type safety and autocomplete everywhere.
🧽 Clean, Scalable, and Flexible
The Query Object Pattern:
- 📦 Bundles all UI state into a single place
- 🔁 Makes it easy to reset or modify parts of the state
- 🧼 Keeps components cleaner and easier to maintain
- 🔗 Plays nicely with API endpoints that accept query parameters
If your React app is dealing with more than 2-3 filters or query parameters, try this pattern. It’s easy to implement, and hard to live without once you start using it.
Tip: You can even sync your query object with the URL using libraries like use-search-params or React Router to make state shareable and bookmarkable.
React doesn’t force you to manage state in any particular way. But patterns like this help you keep control as your UI grows.
Next time you're working on search filters or data-heavy views, remember: One Object to Rule Them All.
If you found this helpful, consider supporting my work at ☕ Buy Me a Coffee.
I currently started learning react .