Using React Query for Data Fetching

Loading

Using React Query for Data Fetching

React Query is a powerful library that simplifies data fetching, caching, synchronization, and background updates in React applications. It handles common scenarios like pagination, infinite scrolling, caching, and retrying failed requests. React Query abstracts many complexities involved in data fetching, making it easier to manage server state in your React application.

Here’s how to use React Query for data fetching in a React app.


1. Installation

To use React Query, you first need to install it.

npm install react-query

You’ll also need to wrap your application in a QueryClientProvider to provide React Query’s functionality to your components.

import { QueryClient, QueryClientProvider } from 'react-query';

const queryClient = new QueryClient();

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      {/* Your application components */}
    </QueryClientProvider>
  );
}

export default App;

2. Fetching Data with React Query

React Query provides a useQuery hook that makes fetching data from APIs incredibly simple.

Basic Example:

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

// Fetch function to get data from an API
const fetchData = async () => {
  const response = await fetch('https://api.example.com/data');
  if (!response.ok) {
    throw new Error('Network response was not ok');
  }
  return response.json();
};

const FetchDataWithReactQuery = () => {
  // Using useQuery hook to fetch data
  const { data, error, isLoading, isError } = useQuery('fetchData', fetchData);

  if (isLoading) {
    return <div>Loading...</div>;
  }

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

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

export default FetchDataWithReactQuery;

Explanation:

  • useQuery: The useQuery hook is used to fetch data. The first argument 'fetchData' is the query key, which uniquely identifies the data. The second argument is the fetch function that returns a promise (e.g., API call).
  • Loading state: While the data is being fetched, isLoading is true, and you can show a loading indicator.
  • Error handling: If there’s an error, isError will be true, and the error message will be displayed.
  • Data: Once the data is fetched successfully, it’s available in the data variable.

3. Query Caching and Background Refetching

React Query automatically caches the fetched data and provides ways to keep it up-to-date by refetching in the background.

Example with Background Refetching:

const FetchDataWithRefetch = () => {
  const { data, error, isLoading, isError, refetch } = useQuery(
    'fetchData',
    fetchData,
    {
      refetchInterval: 5000,  // Automatically refetch every 5 seconds
    }
  );

  if (isLoading) {
    return <div>Loading...</div>;
  }

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

  return (
    <div>
      <h1>Data Fetched:</h1>
      <pre>{JSON.stringify(data, null, 2)}</pre>
      <button onClick={refetch}>Refetch Data</button>
    </div>
  );
};

Explanation:

  • refetchInterval: This option tells React Query to refetch the data periodically (every 5 seconds in this case).
  • refetch: You can manually trigger a refetch by calling the refetch function.

4. Handling Pagination and Infinite Queries

React Query makes handling pagination and infinite scrolling simple with its useInfiniteQuery hook.

Example of Infinite Scrolling with useInfiniteQuery:

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

const fetchPageData = async ({ pageParam = 1 }) => {
  const response = await fetch(`https://api.example.com/data?page=${pageParam}`);
  const data = await response.json();
  return data;
};

const InfiniteScrollData = () => {
  const {
    data,
    error,
    isLoading,
    isError,
    fetchNextPage,
    hasNextPage,
  } = useInfiniteQuery('fetchData', fetchPageData, {
    getNextPageParam: (lastPage, allPages) => lastPage.nextPage, // Assumes API provides the next page info
  });

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

  return (
    <div>
      <h1>Infinite Scrolling Data</h1>
      <ul>
        {data.pages.map((page, index) => (
          <li key={index}>
            {page.items.map(item => (
              <div key={item.id}>{item.name}</div>
            ))}
          </li>
        ))}
      </ul>

      {hasNextPage && (
        <button onClick={() => fetchNextPage()}>Load More</button>
      )}
    </div>
  );
};

export default InfiniteScrollData;

Explanation:

  • useInfiniteQuery: This hook is used to fetch data for paginated APIs. The pageParam argument specifies the current page, and React Query automatically manages it.
  • getNextPageParam: This function tells React Query how to determine the next page. It returns the value of the next page from the last page.
  • fetchNextPage: This function is used to load the next page of data.
  • hasNextPage: This boolean indicates if there is another page of data available to load.

5. Mutations with React Query

React Query not only handles fetching data but also supports mutations, which are operations that modify server-side data (e.g., creating, updating, or deleting records).

Example of Mutation with React Query:

import React from 'react';
import { useMutation, useQueryClient } from 'react-query';

const createData = async (newData) => {
  const response = await fetch('https://api.example.com/data', {
    method: 'POST',
    body: JSON.stringify(newData),
    headers: {
      'Content-Type': 'application/json',
    },
  });
  return response.json();
};

const CreateDataWithMutation = () => {
  const queryClient = useQueryClient();
  const { mutate, isLoading, isError, error } = useMutation(createData, {
    onSuccess: () => {
      // Invalidate or refetch queries after a successful mutation
      queryClient.invalidateQueries('fetchData');
    },
  });

  const handleCreate = () => {
    mutate({ name: 'New Data' });
  };

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

  return (
    <div>
      <h1>Create New Data</h1>
      <button onClick={handleCreate}>Create</button>
    </div>
  );
};

export default CreateDataWithMutation;

Explanation:

  • useMutation: This hook is used for creating, updating, or deleting data on the server.
  • mutate: The function used to trigger the mutation.
  • onSuccess: This callback is executed after the mutation succeeds. It’s often used to invalidate or refetch the query to update the data on the client.
  • invalidateQueries: This tells React Query to refetch the data associated with a specific query key (e.g., fetchData) after a successful mutation.

Leave a Reply

Your email address will not be published. Required fields are marked *