Goodbye Spaghetti State: Query Objects Make React Filters Clean & Easy
davinceleecode

davinceleecode @davinceleecode

Location:
Void
Joined:
Mar 8, 2025

Goodbye Spaghetti State: Query Objects Make React Filters Clean & Easy

Publish Date: May 5
16 4

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,
});
Enter fullscreen mode Exit fullscreen mode

Instead of spreading your state across multiple hooks:

const [genreId, setGenreId] = useState(null);
const [platformId, setPlatformId] = useState(null);
...
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

When your user types into a search bar:

<input
  type="text"
  value={query.searchText}
  onChange={(e) => setQuery({ ...query, searchText: e.target.value })}
/>
Enter fullscreen mode Exit fullscreen mode

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]);
Enter fullscreen mode Exit fullscreen mode

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;
};
Enter fullscreen mode Exit fullscreen mode

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.

Comments 4 total

  • Shifa
    ShifaMay 6, 2025

    I currently started learning react .

    • davinceleecode
      davinceleecodeMay 7, 2025

      That is a good start Shifa! 🌟. Keep pushing! 💪

      • Shifa
        ShifaMay 7, 2025

        yep working on it

  • Israel Rotimi
    Israel RotimiMay 7, 2025

    I like your article, though not building any side projects now.
    But will apply when I'm hired

Add comment