Clark's BlogBack to Portfolio

Tips: Stop Using [isLoading, setIsLoading] = useState(true) — Use useQuery Instead

Published Date: Sat Jun 07 2025

Last updated: Sat Jun 07 2025

blog image

Table of Contents

  • Why useState + useEffect Gets Messy
  • Enter useQuery
  • Why It’s Better
  • Final Thoughts

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.

Why useState + useEffect Gets Messy

At first, managing loading state manually seems fine. But as your app grows, you start adding more logic:

  • What if the fetch fails? You add error handling.
    • What if the component unmounts before the fetch is done?
      • What if you want to refetch the data later?

        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.

        Enter useQuery

        The useQuery hook does everything for you:

        • Handles loading, success, and error states
          • Caches data
            • Refetches when needed
              • Works great with async/await or promise-based functions

                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>;
                };
                

                Why It’s Better

                • ✅ No need for useState or useEffect
                  • ✅ Automatic error handling
                    • ✅ Caching and refetching out of the box
                      • ✅ Cleaner, more maintainable code

                        Final Thoughts

                        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.

                        Back to Top