DEV Community

Cover image for Goodbye Spaghetti State: Query Objects Make React Filters Clean & Easy
davinceleecode
davinceleecode Subscriber

Posted on

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

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.

Top comments (9)

Collapse
 
shifa_2 profile image
Shifa

Thank you all so much for support over the past month!
This community truly kept me going, and to express my gratitude, I’ve written a special article just to say thanks to every one
dev.to/shifa_2/from-zero-to-streak...
It means a lot to be part of such a positive and inspiring space. 🚀
Let’s keep supporting and lifting each other up! ✨

Collapse
 
nathan_tarbert profile image
Nathan Tarbert

been smashing my head against messy state forever so this just hits home for me tbh - you think sticking with one object like this actually makes stuff easier to debug down the line or just delays chaos?

Collapse
 
davinceleecode profile image
davinceleecode

It depends on how disciplined your structure is.
If you clearly define the shape, avoid unecessary nesting, and update state immutably, then yes, it can make debugging easier and your component logic cleaner. But if the object starts growing uncontrolled, it can become harder to reason about than having separate state variables.
I totally get what you mean! I recommend also checking out state management libraries like Zustand or Redux they can really help when your component state starts getting too complex or hard to track. Especially if you’re managing shared or nested state, these tools can make things more maintainable in the long run.

Collapse
 
shifa_2 profile image
Shifa

I currently started learning react .

Collapse
 
davinceleecode profile image
davinceleecode

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

Collapse
 
shifa_2 profile image
Shifa

yep working on it

Collapse
 
anitaolsen profile image
Anita Olsen

How could you post such a cover photo? Now I am craving spaghetti!😅

Collapse
 
davinceleecode profile image
davinceleecode

😂😂😂

Collapse
 
israelrotimi profile image
Israel Rotimi

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