DEV Community

Cover image for Mastering React Query: A Comprehensive Guide
Raghuveer Bharadwaj
Raghuveer Bharadwaj

Posted on

Mastering React Query: A Comprehensive Guide

Tired of juggling Axios and useEffects for API calls and managing dependencies? Say hello to React Query! 🎉 It makes your life easier with automatic caching, synchronization, background updates, and so much more. 🚀

Traditional Way of API Calling

In the traditional way, you typically use Axios inside a useEffect hook to make API calls and manage state manually. Here's an example:

import React, { useState, useEffect } from 'react';
import axios from 'axios';

const TraditionalAPIComponent = () => {
  const [data, setData] = useState(null);
  const [error, setError] = useState(null);
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await axios.get('https://api.example.com/data');
        setData(response.data);
        setIsLoading(false);
      } catch (error) {
        setError(error);
        setIsLoading(false);
      }
    };

    fetchData();
  }, []);

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

  return (
    <div>
      <h1>Data:</h1>
      <pre>{JSON.stringify(data, null, 2)}</pre>
    </div>
  );
};

export default TraditionalAPIComponent;
Enter fullscreen mode Exit fullscreen mode

Using React Query (useQuery)

React Query simplifies data fetching by providing hooks that manage caching, synchronization, and background updates out of the box. Here's how you can do the same thing with React Query:

import React from 'react';
import { useQuery } from 'react-query';
import axios from 'axios';

const fetchData = async () => {
  const { data } = await axios.get('https://api.example.com/data');
  return data;
};

const ReactQueryComponent = () => {
  const { data, error, isLoading } = useQuery('fetchData', fetchData);

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

  return (
    <div>
      <h1>Data:</h1>
      <pre>{JSON.stringify(data, null, 2)}</pre>
    </div>
  );
};

export default ReactQueryComponent;
Enter fullscreen mode Exit fullscreen mode

Adding Dependencies with useQuery

Sometimes, you need to fetch data based on certain dependencies. In the traditional way, you'd do this with useEffect like so:

useEffect(() => {
    // Your fechUserData API call

    fetchUserData(userId);
  }, [userId]);
Enter fullscreen mode Exit fullscreen mode

With React Query, you can handle dependencies by using the queryKey and enabled option:

const { data, error, isLoading } = useQuery(['userData', userId], () => fetchUserData(userId), {
    enabled: !!userId, // Ensure query is enabled only if userId is truthy
  });
Enter fullscreen mode Exit fullscreen mode

Control Cache Time

To control cache timing in React Query, you can utilize the cacheTime option within the useQuery hook. This option dictates how long the fetched data remains in the cache before it's considered outdated and possibly removed. Here's how to implement it:

const { data, error, isLoading } = useQuery('fetchData', fetchData, {
    cacheTime: 3600000, // Cache data for 1 hour (3600000 milliseconds)
  });
Enter fullscreen mode Exit fullscreen mode

Invalidation with useInvalidateQuery

React Query provides the useInvalidateQuery hook to invalidate specific queries. This is useful when you want to refetch data based on certain events, such as user actions or changes in application state.

const { data, error, isLoading } = useQuery('fetchData', fetchData);
  const invalidateQuery = useInvalidateQuery('fetchData');

  const handleButtonClick = () => {
    // Invalidates the 'fetchData' query, triggering a refetch
    invalidateQuery();
  };

Enter fullscreen mode Exit fullscreen mode

Using useMutation for update calls

useMutation is a hook provided by React Query that simplifies data mutation operations in your React components. It encapsulates common tasks such as making HTTP requests, handling loading and error states, and updating data in response to mutations.

const updateUser = async (userData) => {
  const response = await axios.put('https://api.example.com/users', userData);
  return response.data; // Updated user data
};

const [mutate, { isLoading, isError, error, data }] = useMutation(updateUser);

// Execute mutation
const handleUpdateUser = async () => {
  try {
  await mutate({ id: 123, name: 'John Doe', email: 'john@example.com' });
  } catch (error) {
    console.error('An error occurred:', error);
  }
};
Enter fullscreen mode Exit fullscreen mode

Using useInfiniteQuery for paginated API calls

useInfiniteQuery is a hook provided by React Query that simplifies pagination operations in your React components. It enables infinite scrolling by fetching data in chunks as the user scrolls, providing a seamless and efficient browsing experience.

import React from 'react';
import { useInfiniteQuery } from 'react-query';
import axios from 'axios';

// Define fetch function
const fetchPosts = async ({ pageParam = 1 }) => {
  const response = await axios.get(`https://api.example.com/posts?page=${pageParam}`);
  return response.data;
};

const PostList = () => {
  const {
    data,
    fetchNextPage,
    hasNextPage,
    isFetchingNextPage,
    isError,
    error,
  } = useInfiniteQuery('posts', fetchPosts, {
    getNextPageParam: (lastPage, allPages) => lastPage.nextPage, // Extract next page number
  });

  return (
    <div>
      {data.pages.map((page, index) => (
        <React.Fragment key={index}>
          {page.posts.map((post) => (
            <div key={post.id}>{post.title}</div>
          ))}
        </React.Fragment>
      ))}
      {isError && <div>Error: {error.message}</div>}
      {hasNextPage && (
        <button onClick={() => fetchNextPage()} disabled={isFetchingNextPage}>
          {isFetchingNextPage ? 'Loading more...' : 'Load More'}
        </button>
      )}
    </div>
  );
};

export default PostList;

Enter fullscreen mode Exit fullscreen mode

Conclusion

In wrapping up, React Query's hooks are like magic wands for handling data in React apps! Whether it's fetching data with useQuery, updating with useMutation, or endless scrolling with useInfiniteQuery, React Query simplifies everything. It's the secret sauce that makes building React apps a breeze, freeing you to focus on creating awesome user experiences. So wave goodbye to data headaches and hello to smooth sailing with React Query! ✨🚀

Top comments (0)