Mahamudul Hasan Rubel
HomeAboutProjectsSkillsExperienceBlogPhotosContact
Mahamudul Hasan Rubel

Senior Software Engineer crafting high-performance web applications and SaaS platforms.

Navigation

  • Home
  • About
  • Projects
  • Skills
  • Experience
  • Blog
  • Photos
  • Contact

Get in Touch

Available for senior/lead roles and consulting.

bd.mhrubel@gmail.comHire Me

© 2026 Mahamudul Hasan Rubel. All rights reserved.

Built with using Next.js 16 & Tailwind v4

Back to Blog
ReactNext.jsJune 20, 20264 min read

Fetching data in a React component the right way

Fetching data in a React component the right way isn't just about calling an API. Avoid common useEffect traps and build faster, more stable apps today.

ReactNext.jsFrontend DevelopmentJavaScriptWeb PerformanceTutorial
Close-up of JavaScript code on a laptop screen, showcasing programming in progress.

Last month, I spent three days debugging a race condition in a dashboard that was flickering every time a user toggled a filter. The issue? A simple useEffect hook that was triggering multiple network requests without cleaning up, causing the UI to jump between outdated states.

If you’re still fetching data directly inside your components using standard lifecycle hooks, you’re likely creating more work for yourself than you realize. Let’s clean this up.

Why useEffect isn't the data fetching silver bullet

When you’re starting out, it feels natural to drop a fetch call inside a useEffect. It works for the simplest prototypes, but it fails in production. You run into issues like:

  • Race conditions: The second request finishes before the first, overwriting your data with stale information.
  • Request waterfalls: Components down the tree wait for parent data, blocking the UI.
  • Lack of caching: Every time the component re-renders or mounts, you hit the network again.

We’ve all been there. My team once tried to solve this by adding a complex isMounted flag inside our hooks. It turned into a mess of boilerplate that made the code nearly unreadable. We realized we were fighting the framework instead of working with it.

The right way to handle data

Multiple no left turn traffic signs displayed together under a blue sky.

Instead of building your own fetching layer from scratch, lean on tools designed for the job. If you’re building a standard React application, libraries like TanStack Query (React Query) have become the industry standard for good reason. They handle caching, background updates, and request deduping out of the box.

If you're using Next.js, the landscape shifts again. You should be leveraging server components vs client components: A practical guide to decide where your data lives. Often, you don't even need useEffect because you can fetch data directly on the server and pass it as props.

When you must fetch on the client

Sometimes, you need to fetch data based on user interaction (like a search bar). Here is how I structure a clean, robust fetching pattern using modern React hooks:

JAVASCRIPT
import { useQuery } from CE9178">'@tanstack/react-query';

function UserProfile({ userId }) {
  const { data, isLoading, error } = useQuery({
    queryKey: [CE9178">'user', userId],
    queryFn: () => fetch(CE9178">`/api/users/${userId}`).then(res => res.json()),
  });

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error loading data</div>;

  return <h1>{data.name}</h1>;
}

By using queryKey, the library automatically knows that if the userId changes, it needs to fetch new data. It handles the cleanup, the loading states, and the caching logic for you. This approach is drastically more maintainable than manual useState and useEffect orchestration, which I’ve covered extensively in my guide on useState and useEffect: A Mental Model for React Beginners.

Rethinking your data architecture

Before you write that next fetch call, step back. Ask yourself: does this data need to be fetched on the client?

If you are using the Next.js App Router, you should look into caching and revalidation in the Next.js App Router: A practical guide. Often, the best way to handle data is to stop "fetching" it entirely and start "loading" it via server-side props. This eliminates the need for loading spinners and reduces your bundle size by moving the logic away from the browser.

Common pitfalls to watch out for

A surprised man in a leather jacket peers through binoculars with a shocked expression.

  1. Over-fetching: Don't pull the whole user object if you only need the display name.
  2. Ignoring errors: A catch block is the bare minimum. Always provide a fallback UI for when the network fails.
  3. Mixing concerns: Keep your API logic separate from your UI components. Create custom hooks like useUser instead of calling fetch inside your JSX.

I still catch myself trying to write quick-and-dirty useEffect calls when I'm prototyping. It’s tempting because it's fast. But every time I do, I end up refactoring it three hours later because the application state becomes unpredictable.

Next time, I’ll probably reach for a specialized library from the start. What about you? Are you still wiring up useEffect for every API request, or have you started moving that logic to the server?

Frequently Asked Questions

Q: Is it ever okay to use useEffect for fetching? A: Only for very small, non-critical features or single-page prototypes. For anything that needs to be reliable, use a dedicated data-fetching library.

Q: Do I need React Query if I use Next.js Server Components? A: Not necessarily. Server components handle data fetching natively. You mostly need React Query for client-side interactivity, like polling or real-time updates.

Q: How do I prevent multiple requests? A: By using a library with built-in deduplication or by ensuring your queryKey is correctly tied to your dependencies in React.

Fetching data in a React component the right way is ultimately about reducing complexity. Move your logic to the server where you can, and use battle-tested libraries on the client where you must. Your future self will thank you.

Back to Blog

Similar Posts

Close-up of JavaScript code on a laptop screen, showcasing programming in progress.
ReactNext.jsJune 20, 20264 min read

React props and state: Where your data should live

React props and state management can be confusing. Learn the right way to structure your data, avoid prop drilling, and keep your components predictable.

Read more
Detailed view of a network switch featuring multiple ethernet ports and LED indicators.
Next.jsReactJune 20, 20264 min read

Caching and revalidation in the Next.js App Router: A Practical Guide

Caching and revalidation in the Next.js App Router are often misunderstood. Learn how to control the Data Cache and keep your production data fresh today.

Read more
Close-up of JavaScript code on a laptop screen, showcasing programming in progress.
ReactNext.jsJune 20, 20264 min read

Profiling and fixing a slow React render: A Practical Guide

Profiling and fixing a slow React render is easier when you stop guessing. Learn how to use React DevTools to find bottlenecks and optimize your app.

Read more