Back to Blog
Lesson 26 of the Intermediate React: Hooks, State & Data Patterns course
ReactJune 26, 20263 min read

Integrating Live Data into the Dashboard with React Query

Learn to fetch dashboard metrics, manage loading states, and implement background polling in your React application using React Query for live data.

ReactReact QueryDashboardAPIFrontendjavascript

Previously in this course, we explored synchronizing client and server state and mastered mutations and data updates. Now that we’ve established how to handle mutations, this lesson shifts focus to the "read" side of our dashboard: keeping our UI current with live API data using React Query.

The Dashboard Data Lifecycle

In a production dashboard, data isn't static. Users expect to see the latest metrics without manually refreshing the browser. While we’ve covered caching strategies to optimize network requests, we now need to explicitly configure our queries to behave like a "live" feed.

React Query handles the heavy lifting of the asynchronous lifecycle. When you fetch data, you get back more than just the result; you get flags for isLoading, isFetching, and isError. These are your building blocks for a professional-grade user experience.

Fetching and Polling Metrics

Let's update our DashboardStats component. We want to fetch a set of core metrics and ensure the component polls the server for updates every 5 seconds.

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

const fetchDashboardMetrics = async () => {
  const response = await fetch(CE9178">'/api/stats');
  if (!response.ok) throw new Error(CE9178">'Failed to fetch metrics');
  return response.json();
};

export const DashboardStats = () => {
  const { data, isLoading, isError, error } = useQuery({
    queryKey: [CE9178">'dashboard-metrics'],
    queryFn: fetchDashboardMetrics,
    // Polling every 5 seconds
    refetchInterval: 5000,
    // Keep the previous data while fetching in the background
    placeholderData: (previousData) => previousData,
  });

  if (isLoading) return <div>Loading live metrics...</div>;
  if (isError) return <div>Error: {error.message}</div>;

  return (
    <div className="stats-grid">
      <StatCard title="Active Users" value={data.activeUsers} />
      <StatCard title="Revenue" value={CE9178">`$${data.revenue}`} />
    </div>
  );
};

Key Concepts for Live Updates

  1. refetchInterval: This is the simplest way to implement "live" data. By setting this to a number (in milliseconds), React Query will automatically trigger a background refetch.
  2. isFetching vs isLoading: isLoading is only true for the initial fetch. isFetching is true whenever a request is in flight, including background polling. Use isFetching if you want to show a subtle "updating" spinner without unmounting the whole component.
  3. placeholderData: Notice how we use placeholderData to preserve the previous state during background updates. This prevents the dashboard from "flickering" or showing empty states every time the background poll occurs.

Hands-on Exercise

In your current dashboard project, locate your Overview component.

  1. Implement a useQuery hook to fetch your main dashboard data.
  2. Add a refetchInterval of 10,000ms.
  3. Add a small visual indicator (a simple <span>) that renders only when isFetching is true, informing the user that the dashboard is currently updating.

Common Pitfalls

  • Over-polling: Setting refetchInterval too low (e.g., under 1-2 seconds) can overwhelm your server and increase API costs. Always evaluate if your data actually changes that frequently.
  • Ignoring staleTime: If your staleTime is set to Infinity, your query will never refetch unless you trigger it manually, even if you set a refetchInterval. Ensure your staleTime is lower than your polling interval.
  • Component Unmounting: Remember that refetchInterval stops when the component unmounts. If you need the data to update even when the user is on a different tab, you should move the query to a higher-level provider or use the refetchIntervalInBackground option.

Recap

We’ve successfully transformed our static dashboard into a reactive one. By leveraging useQuery, we’ve handled the initial fetch, provided graceful loading states, and automated background synchronization. This ensures our users always see the latest data without sacrificing performance.

Up next: We will dive into creating robust error boundaries and reusable loading skeletons to polish the user experience when API calls inevitably fail.

Similar Posts