DEV Community

Abhay Singh Kathayat
Abhay Singh Kathayat

Posted on

React Query (TanStack Query): Efficient Data Fetching and State Management for React

React Query (TanStack Query): A Powerful Data Fetching and State Management Library for React

React Query (now called TanStack Query) is an extremely popular data-fetching and state management library for React applications. It simplifies working with remote data by handling the complexities of data fetching, caching, synchronization, and pagination. React Query abstracts away much of the manual process involved in making API requests, storing and updating data, and managing loading states.

TanStack Query helps developers manage server-state in React applications with minimal setup, ensuring a smooth user experience, especially when dealing with asynchronous operations.


1. What is React Query (TanStack Query)?

React Query is a data-fetching and state management tool that helps in simplifying the process of interacting with server-side data in React applications. It abstracts and manages the fetching, caching, synchronization, and background updating of data.

It’s primarily used to manage server-state, which refers to data that comes from a remote server or API, like data from REST APIs, GraphQL, or any other data source.

Key Features:

  • Automatic Caching: React Query automatically caches fetched data, which allows for faster subsequent data fetching without extra network requests.
  • Automatic Synchronization: It ensures your data stays in sync between the client and server, even when the user switches between pages or revisits the app.
  • Background Fetching: React Query can automatically refetch data in the background to ensure the user always has the most up-to-date data.
  • Polling and Pagination: React Query supports polling and pagination out of the box, which simplifies these common tasks.

2. Core Concepts of React Query

1. Queries

Queries in React Query are used to fetch data from a server (or any external data source). A query is identified by a unique key, which React Query uses to cache and track the data.

Example:

import { useQuery } from 'react-query';

function fetchPosts() {
  return fetch('https://jsonplaceholder.typicode.com/posts')
    .then((response) => response.json());
}

const Posts = () => {
  const { data, error, isLoading } = useQuery('posts', fetchPosts);

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error fetching posts</div>;

  return (
    <ul>
      {data.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
};
Enter fullscreen mode Exit fullscreen mode
  • useQuery hook fetches the data using the fetchPosts function. The posts string is the unique key, and React Query will cache the fetched data under this key.

2. Mutations

Mutations are used to modify or create data on the server (e.g., POST, PUT, DELETE requests). Like queries, mutations can be tracked and automatically update your state after a successful mutation.

Example:

import { useMutation } from 'react-query';

function createPost(postData) {
  return fetch('https://jsonplaceholder.typicode.com/posts', {
    method: 'POST',
    body: JSON.stringify(postData),
    headers: { 'Content-Type': 'application/json' },
  }).then((response) => response.json());
}

const NewPost = () => {
  const mutation = useMutation(createPost);

  const handleCreatePost = async () => {
    await mutation.mutate({ title: 'New Post', body: 'This is a new post' });
  };

  return (
    <div>
      <button onClick={handleCreatePost}>Create Post</button>
      {mutation.isLoading ? <p>Creating post...</p> : null}
      {mutation.isError ? <p>Error creating post</p> : null}
      {mutation.isSuccess ? <p>Post created!</p> : null}
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode
  • useMutation hook is used for operations like creating, updating, or deleting data.

3. Caching

React Query automatically caches the results of queries. This caching allows for faster rendering and avoids making duplicate requests to the server. Cached data is automatically updated when a query is refetched.

You can customize the caching behavior to suit your app’s needs, like setting a cache time or specifying a stale time (the time after which the cached data is considered stale).

Example:

const { data } = useQuery('posts', fetchPosts, {
  staleTime: 1000 * 60 * 5, // Cache is fresh for 5 minutes
  cacheTime: 1000 * 60 * 30, // Cache persists for 30 minutes
});
Enter fullscreen mode Exit fullscreen mode

4. Pagination

React Query provides built-in support for pagination. You can fetch paginated data with custom page and limit parameters, and it will cache the responses appropriately.

Example:

const fetchPage = (page) => fetch(`https://jsonplaceholder.typicode.com/posts?_page=${page}&_limit=10`)
  .then((res) => res.json());

const PaginatedPosts = () => {
  const [page, setPage] = React.useState(1);
  const { data, isLoading, isError } = useQuery(['posts', page], () => fetchPage(page));

  if (isLoading) return <div>Loading...</div>;
  if (isError) return <div>Error</div>;

  return (
    <div>
      <ul>
        {data.map((post) => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
      <button onClick={() => setPage((prev) => prev - 1)} disabled={page === 1}>
        Previous
      </button>
      <button onClick={() => setPage((prev) => prev + 1)}>Next</button>
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode
  • The useQuery hook is used with an array key (['posts', page]) to fetch paginated data.

3. Installing and Setting Up React Query (TanStack Query)

To use React Query, you'll need to install react-query (TanStack Query):

npm install react-query
Enter fullscreen mode Exit fullscreen mode

1. Setting Up React Query Provider

To enable React Query in your application, you need to wrap your root component in the QueryClientProvider to provide the necessary context to the entire app.

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

const queryClient = new QueryClient();

const App = () => (
  <QueryClientProvider client={queryClient}>
    <YourApp />
  </QueryClientProvider>
);
Enter fullscreen mode Exit fullscreen mode
  • QueryClient is the core object of React Query. It manages all the queries and mutations in your app.

4. Advanced Features of React Query

1. Pagination and Infinite Query

React Query supports pagination and infinite scrolling with useInfiniteQuery, allowing you to handle infinite lists and pagination.

Example:

import { useInfiniteQuery } from 'react-query';

function fetchPostsPage({ pageParam = 1 }) {
  return fetch(`https://jsonplaceholder.typicode.com/posts?_page=${pageParam}`)
    .then((res) => res.json());
}

const InfinitePosts = () => {
  const {
    data,
    fetchNextPage,
    hasNextPage,
    isLoading,
    isFetchingNextPage,
  } = useInfiniteQuery('posts', fetchPostsPage, {
    getNextPageParam: (lastPage, allPages) => lastPage.length === 10 ? allPages.length + 1 : false,
  });

  return (
    <div>
      {isLoading ? <div>Loading...</div> : null}
      {data?.pages.map((page, i) => (
        <div key={i}>
          {page.map((post) => (
            <p key={post.id}>{post.title}</p>
          ))}
        </div>
      ))}
      <button onClick={() => fetchNextPage()} disabled={!hasNextPage || isFetchingNextPage}>
        {isFetchingNextPage ? 'Loading more...' : hasNextPage ? 'Load More' : 'No more posts'}
      </button>
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

2. Query Invalidations

You can invalidate a query manually using queryClient.invalidateQueries. This forces a refetch of the data for the specified query key.

Example:

import { useQueryClient } from 'react-query';

const mutation = useMutation(createPost, {
  onSuccess: () => {
    queryClient.invalidateQueries('posts');
  },
});
Enter fullscreen mode Exit fullscreen mode
  • This ensures that after creating a new post, the list of posts is refetched automatically.

5. Benefits of Using React Query

1. Simplified Data Fetching

React Query reduces the boilerplate for handling loading, success, and error states, making data fetching easier and more declarative.

2. Automatic Caching

Data fetched is cached by default, reducing unnecessary network requests and speeding up your app.

3. Background Updates

React Query provides background data fetching, ensuring that your app’s data stays fresh even when it's not explicitly refetched.

4. Built-in Pagination and Infinite Queries

Handling pagination and infinite scrolling is simple and efficient with React Query’s built-in hooks.

5. DevTools for Debugging

React Query provides an excellent DevTools interface for inspecting queries, mutations, and their states in real-time.


**6. Conclusion

**

React Query (TanStack Query) provides an efficient and scalable way to handle data-fetching and state management in React applications. With built-in caching, background fetching, pagination, and error handling, React Query makes interacting with server-side data easy and seamless.


Top comments (0)