Published Date: Sat Jun 07 2025
Last updated: Sat Jun 07 2025
If you’re fetching data in a React app, chances are you’ve written something like this:
const [data, setData] = useState(null);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
fetch("/api/data")
.then((res) => res.json())
.then((result) => {
setData(result);
setIsLoading(false);
});
}, []);
This works — but there’s a better way.
useState
+ useEffect
Gets MessyAt first, managing loading state manually seems fine. But as your app grows, you start adding more logic:
Suddenly, what started as a few lines becomes a tangle of state, effects, and conditionals. This is where libraries like React Query (now known as TanStack Query) come in.
useQuery
The useQuery
hook does everything for you:
Here’s how your code looks with useQuery
:
import { useQuery } from "@tanstack/react-query";
const fetchData = async () => {
const res = await fetch("/api/data");
if (!res.ok) throw new Error("Network response was not ok");
return res.json();
};
const MyComponent = () => {
const { data, isLoading, error } = useQuery({
queryKey: ["myData"],
queryFn: fetchData,
});
if (isLoading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
return <pre>{JSON.stringify(data, null, 2)}</pre>;
};
useState
or useEffect
It’s totally okay to start with useState
and useEffect
when you're learning. But as soon as you're doing more than a simple fetch, switching to useQuery
will save you a lot of time and headaches.
If you're not using it yet, give it a try — it’s one of those tools that feels like magic once you get the hang of it.