React query use example

Unlocking the Power of TanStack React Query: A Must-Know for Web Developers

Abdellah Slimani

Abdellah Slimani

May 28, 2024
280 views
5 min read

In the fast-paced world of web development, efficient data fetching and state management are paramount. Enter TanStack React Query, a powerful library that addresses these challenges head-on. Designed to simplify and enhance the way React developers handle server-state in their applications, React Query is a must-know tool for modern web development. This blog post will provide a comprehensive introduction to TanStack React Query, making it a go-to resource for web developers who want to learn and leverage this library in their projects.

What is TanStack React Query?

TanStack React Query is a data-fetching and state management library for React applications. It abstracts away much of the boilerplate code involved in managing server state, providing a set of hooks that simplify the process of fetching, caching, synchronizing, and updating server state.

Why Should React Developers Use TanStack React Query?

  1. Simplified Data Fetching: React Query reduces the complexity of data fetching in React applications. It handles caching, background updates, and stale data out of the box.
  2. Improved Performance: By managing cache invalidation and background refetching, React Query ensures that your application remains performant and responsive.
  3. Enhanced Developer Experience: The library provides an intuitive API and comprehensive dev tools, making it easier for developers to debug and optimize their applications.
  4. Optimistic Updates: React Query supports optimistic updates, allowing your UI to remain responsive by assuming successful mutation and updating the state immediately.
  5. Automatic Refetching: It automatically refetches data when needed, ensuring that your application displays the most current data without manual intervention.

Getting Started with TanStack React Query

To demonstrate the power of TanStack React Query, let’s walk through a basic example of how to use it in a React application.

Step 1: Installation

First, you need to install @tanstack/react-query and @tanstack/react-query-devtools:

npm install @tanstack/react-query @tanstack/react-query-devtools


Step 2: Setting Up the Query Client

Next, set up the QueryClient and QueryClientProvider in your application. This provides the context for React Query to manage server state.

import React from 'react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';

const queryClient = new QueryClient();

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <YourComponent />
      <ReactQueryDevtools initialIsOpen={false} />
    </QueryClientProvider>
  );
}

Step 3: Fetching Data with useQuery

Using the useQuery hook, you can fetch data from an API and handle various states (loading, error, success) seamlessly.

import React from 'react';
import { useQuery } from '@tanstack/react-query';

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

function Todos() {
  const { data, error, isLoading } = useQuery('todos', fetchTodos);

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

  return (
    <ul>
      {data.map(todo => (
        <li key={todo.id}>{todo.title}</li>
      ))}
    </ul>
  );
}

Step 4: Mutating Data with useMutation

React Query also provides a useMutation hook for handling data mutations such as POST, PUT, and DELETE requests.

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

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

function AddTodo() {
  const queryClient = useQueryClient();
  const mutation = useMutation(addTodo, {
    onSuccess: () => {
      // Invalidate and refetch
      queryClient.invalidateQueries('todos');
    },
  });

  const handleSubmit = (event) => {
    event.preventDefault();
    const newTodo = {
      title: event.target.elements.todo.value,
      completed: false,
    };
    mutation.mutate(newTodo);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input name="todo" type="text" />
      <button type="submit">Add Todo</button>
    </form>
  );
}

Creating Custom Hooks with TanStack React Query

One of the powerful features of React Query is its flexibility, which allows developers to create custom hooks tailored to their specific needs. Custom hooks enable you to encapsulate logic related to data fetching and state management, promoting code reusability and maintainability. In this section, we’ll explore how to create custom hooks using React Query.

Why Use Custom Hooks?

  • Code Reusability: Encapsulate complex logic into reusable hooks.
  • Separation of Concerns: Keep your components clean and focused on rendering UI.
  • Consistency: Standardize how data fetching and state management are handled across your application.

Example: Creating a Custom Hook for Fetching Todos

Let’s create a custom hook to fetch a list of todos from an API. This custom hook will encapsulate the data fetching logic and return the necessary state and data.


Step 1: Define the Fetch Function

First, define a function that fetches data from the API. This function will be used inside our custom hook.

const fetchTodos = async () => {
  const response = await fetch('https://jsonplaceholder.typicode.com/todos');
  if (!response.ok) {
    throw new Error('Network response was not ok');
  }
  return response.json();
};

Step 2: Create the Custom Hook

Next, create a custom hook that uses the useQuery hook from React Query. This custom hook will handle the data fetching and return the necessary states.

import { useQuery } from '@tanstack/react-query';

const useTodos = () => {
  return useQuery('todos', fetchTodos);
};

Step 3: Use the Custom Hook in a Component

Now, you can use the custom hook in any component to fetch and display the todos. This keeps the component clean and focused on rendering.

import React from 'react';
import useTodos from './hooks/useTodos'; // Adjust the path as needed

const TodosComponent = () => {
  const { data: todos, error, isLoading } = useTodos();

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

  return (
    <ul>
      {todos.map(todo => (
        <li key={todo.id}>{todo.title}</li>
      ))}
    </ul>
  );
};

export default TodosComponent;

Example: Creating a Custom Hook for Adding Todos

Custom hooks can also be created for mutations. Let’s create a custom hook for adding a new todo.

Step 1: Define the Mutation Function

First, define a function that adds a new todo to the API.

const addTodo = async (newTodo) => {
  const response = await fetch('https://jsonplaceholder.typicode.com/todos', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(newTodo),
  });
  if (!response.ok) {
    throw new Error('Network response was not ok');
  }
  return response.json();
};

Step 2: Create the Custom Hook

Create a custom hook that uses the useMutation hook from React Query. This custom hook will handle the mutation logic.

import { useMutation, useQueryClient } from '@tanstack/react-query';

const useAddTodo = () => {
  const queryClient = useQueryClient();

  return useMutation(addTodo, {
    onSuccess: () => {
      // Invalidate and refetch the todos query
      queryClient.invalidateQueries('todos');
    },
  });
};

Step 3: Use the Custom Hook in a Component

Use the custom hook in a component to add a new todo.

import React from 'react';
import useAddTodo from './hooks/useAddTodo'; // Adjust the path as needed

const AddTodoComponent = () => {
  const { mutate } = useAddTodo();

  const handleSubmit = (event) => {
    event.preventDefault();
    const newTodo = {
      title: event.target.elements.todo.value,
      completed: false,
    };
    mutate(newTodo);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input name="todo" type="text" />
      <button type="submit">Add Todo</button>
    </form>
  );
};

export default AddTodoComponent;
Creating custom hooks with TanStack React Query is a powerful way to encapsulate and reuse data fetching and state management logic in your React applications. By following the steps outlined in this section, you can create custom hooks that enhance code maintainability and streamline the development process. Custom hooks not only make your code more organized but also promote consistency and efficiency in handling server state across your application.

Utilizing React Query Devtools

React Query Devtools is a powerful companion tool that provides a visual interface for debugging and optimizing your React Query operations. It helps you monitor your queries, mutations, and their states in real-time.

Setting Up React Query Devtools

After installing @tanstack/react-query-devtools, include it in your project as shown in the setup above. The dev tools can be toggled on or off using the initialIsOpen prop.

Key Features of React Query Devtools

  1. Query Explorer: View all the queries in your application, including their status, data, and metadata.
  2. Mutation Explorer: Monitor the status and details of all mutations.
  3. Cache Management: Inspect and manage your query cache, including manually triggering refetches or invalidations.
  4. Debugging: Easily identify and resolve issues related to data fetching and state management.

Here’s how you can access and utilize React Query Devtools in your application:

import { ReactQueryDevtools } from '@tanstack/react-query-devtools';

// Add <ReactQueryDevtools /> inside the <QueryClientProvider> in your main component

<QueryClientProvider client={queryClient}>
  <YourComponent />
  <ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>

Advanced Usage and Best Practices

To truly harness the power of TanStack React Query, consider these advanced tips and best practices:

  1. Prefetching Data: Use queryClient.prefetchQuery to fetch data ahead of time, improving the perceived performance of your application.
  2. Pagination and Infinite Queries: Implement pagination and infinite scrolling with ease using React Query’s built-in support.
  3. Error Handling: Customize error handling logic to provide a better user experience and streamline debugging.
  4. Custom Query Functions: Write custom query functions to handle complex data-fetching scenarios, ensuring flexibility and scalability.
  5. Optimistic Updates: Implement optimistic updates to keep your UI responsive and provide instant feedback to users.

Conclusion

TanStack React Query is a game-changer for React developers, offering a robust solution for managing server state with ease. By simplifying data fetching, improving performance, and enhancing the developer experience, React Query empowers developers to build more efficient and maintainable applications. The addition of React Query Devtools further enriches the development experience by providing powerful debugging and optimization tools.

Start integrating React Query and React Query Devtools into your projects today and experience the benefits firsthand. The comprehensive documentation and active community support make it easier than ever to get started and overcome any challenges you might face. Embrace the power of React Query and elevate your web development skills to the next level.

By following this guide, web developers will have a solid starting point for exploring and mastering TanStack React Query, setting a new standard for efficient and maintainable React applications.