React Query has taken the React world by storm. If you’ve ever struggled with managing async data, caching, or synchronization between components, you’ve probably heard someone say: “Just use React Query”.
But wait—if React Query handles your API data, is that still state? Or is it just data?
In this blog post, we’ll explore what React Query does, what makes something “state,” and how React Query fits into your mental model as a developer.
🧠 What does react query do?
React Query is a data-fetching library for React. It handles:
- ✅ Fetching data from APIs
- ✅ Caching
- ✅ Synchronization across tabs/components
- ✅ Automatic refetching (on focus, intervals, etc.)
- ✅ Background updates
Here’s a simple example:
import { useQuery } from '@tanstack/react-query';
const fetchUsers = async () => {
const res = await fetch('/api/users');
return res.json();
};
function Users() {
const { data, isLoading } = useQuery(['users'], fetchUsers);
if (isLoading) return <p>Loading...</p>;
return (
<ul>
{data.map(user => <li key={user.id}>{user.name}</li>)}
</ul>
);
}
Looks like a typical stateful component… but is data
really part of the state?
🤔 State vs data: what’s the difference?
Let’s clear this up:
Concept | Definition |
State | Data that your app creates or controls during a session. It usually changes based on user interaction. |
Data | Information that comes from outside your app (like APIs). It's often static until refreshed. |
In other words:
If you control it, it’s state. If the server controls it, it’s data.
React’s built-in useState
or useReducer
are perfect for managing local state: toggles, input values, modal visibility, form data, etc.
But for server responses? That’s where React Query shines.
🔁 React query handles “server state”
React Query isn’t a replacement for useState
, useReducer
, or Redux. It manages server state—data that lives on the server but that your UI needs to reflect.
Why does this matter?
Because server state is different from local UI state:
Feature | Local State (useState ) | Server State (React Query) |
Controlled by | The component | The server |
Source | Local interactions | Remote API |
Persistence | Gone on refresh | Can be cached, refetched |
Updates | Manual (setState) | Automatic (refetch, invalidation) |
So when you use React Query, you're saying:
> “This data belongs to the server. I want to consume it, not control it.”
⚙️ So… is it state?
Yes and no.
React Query’s data is stateful—it can change over time, trigger re-renders, and live in memory.
But it’s not React local state. You don’t use setData()
to update it manually. Instead, you:
- Let React Query fetch and cache it
- Use mutations or invalidations to trigger changes
- React to it using hooks like
useQuery
anduseMutation
So we could say:
> React Query gives you data as state, but not your state.
🔥 Why this distinction matters
Understanding the difference helps you:
- Choose the right tool: use
useState
for UI toggles,useQuery
for API calls. - Avoid over-engineering: you don't need Redux or context just to share data.
- Structure your app better: let each layer (UI vs data) handle what it’s best at.
✅ Quick recap
- ✅ State is data you own and control (e.g., modal open/close, form inputs).
- ✅ Data (especially from APIs) is best handled by tools like React Query.
- ✅ React Query manages server state: it's stateful, but you're not manually setting it.
- ✅ Use local state for UI behavior, and React Query for external data.
💡 Final thoughts
React Query bridges the gap between your frontend and the backend. It gives you a structured, powerful way to handle data that lives outside your app, but that your app depends on.
You don’t need to pick between state and data, you just need to know who owns it.
If it comes from the server, treat it like data and let React Query manage it.
If it's based on user interaction, it probably belongs in local state.
Knowing the difference is key to writing clean, efficient React apps.