Fetching data with TanStack Query (React Query)


Objectives

Learn the advantages of using React Query over useEffect for data fetching.

Tech Stack

Create a Vite application

Follow the Vite official documentation to create a vite project with React and TypeScript.

npm create vite@latest

The Vite prompt will assist you in selecting the tech stack you prefer.

After setting up the project, you can see your web application hosting on your localhost. Something like this:

Vite Project Walkthrough

In the vite project, you can find a main.tsx under the src folder, this file serves as the starting point for your React application. It is responsible for importing and rendering the root React component of your application. Later on I will swap the content of App component (App.tsx) with the TodoList component.

File structure of a Vite Application

What is .tsx file ?

A .tsx file is a file extension used for TypeScript files that contain JSX (JavaScript XML) syntax.

JSX is an extension to JavaScript that allows you to write HTML-like code within your JavaScript or TypeScript files. It is commonly used with libraries like React to define the structure and layout of components. By using .tsx file extension, you can write TypeScript code with JSX syntax, combining the type safety and benefits of TypeScript with the expressive power of JSX.

Original Approach: useEffect()

Typically, we use the useEffect hook and axios library to fetch API data in a React application (In this blog post, we want to fetch a list of todos from API). Here's an example of how you can achieve this:

Let's walk through the code:

  • Define a functional component TodoList that utilizes the useState hook to manage the fetched data.
  • Inside the useEffect hook, we define an asynchronous function fetchData that performs the API call using axios.get.
  • The response data is then set using setTodos.

However

This approach requires manually handle API data fetching and state management, which is kind of tedious and error-prone. We can do it a better way! Let's see how we can use TanStack Query to simplify the process.

TanStack Query Approach: useQuery()

Installation

First, install react-query to the project

npm i react-query

Wrap the app

After npm install, modify the code in main.tsx and wrap the app in the client.

Fetch data with useQuery()

Now we can replace the useEffect hook with the useQuery API to fetch data. To do this, we need to import the useQuery hook from react-query. Then, we can replace the useEffect hook with the useQuery hook. Here's how it looks like:

Replace your App component to this TodoList component and you should see something like this on the browser:

Let's see what we achieve here:

  • Simplified Data Fetching: useQuery simplifies the process of fetching data from APIs by providing a declarative and intuitive way to define queries. It abstracts away much of the boilerplate code required for handling data fetching.
  • Error and Loading States: The useQuery hook manages the loading and error states for you. It provides loading indicators while data is being fetched and handles error handling and retries transparently. This simplifies the UI logic, making it easier to display loading spinners or error messages without manual handling of state variables.
  • Abstraction of API Libraries: By using useQuery, you can abstract away the implementation details of specific API libraries. This allows you to switch between different API libraries without making significant changes to your codebase, promoting code modularity and maintainability.

Best Practice: Decouple the code

Seperate the previous code to two files: ./hooks/useTodos.ts and TodoList.tsx. It is a good practice to seperate the user interface and the logic.

The logic

The user interface

By decoupling the code, you can break it down into smaller modules or components. Each module focuses on a specific functionality or feature. This modular structure makes the code easier to understand, maintain, and update. It also facilitates code reusability, as individual modules can be reused in different parts of the application.

Conclusion

useEffect vs. useQuery

  • Simplicity: Using useEffect and axios directly requires writing more code to handle data fetching, caching, and state management.
  • Error Handling: React query handles error and retrying requests out-of-the-box. It automatically retries failed requests based on configurable rules and provides options for custom error handling and exponential backoff strategies. With useEffect and axios, you would need to manually handle error cases and implement retry logic.
  • Integration with UI: React Query provides a powerful integration with UI libraries like React, making it easier to handle loading and error states, as well as displaying optimistic updates. It offers features like isLoading, isError, and isFetching that can be used to conditionally render UI components based on the data fetching status.