Supercharging Data Fetching in React with Custom Hooks and React-Query

Supercharging Data Fetching in React with Custom Hooks and React-Query


4 min read

Section 1: Setting up React Query

React Query is a powerful library that simplifies data fetching and state management in React applications. It provides an elegant way to handle asynchronous operations and cache data for improved performance. Let's get started by setting up React Query in our project.

To install React Query, you can use the following command:

npm install @tanstack/react-query

Once installed, you can import the necessary dependencies:

import { useQuery } from "@tanstack/react-query";
import Cookies from "js-cookie";

The useQuery hook is provided by React Query and allows us to fetch data from an API. We'll also be using the Cookies library to handle authentication tokens.

Now, let's take a look at the fetchApi function:

const fetchApi = async () => {
  const response = await request({
    url: "/your-end-point",
    method: "GET",
  return response?.data?.data;

Section 2: Creating the Custom Hook

Custom hooks are a powerful concept in React that allows us to encapsulate and reuse logic across multiple components. Let's create a custom hook called useUsers that leverage React Query to fetch user data.

const GET_API_NAME = 'your-api-name';

const useApiQuery = () => {
  const token = Cookies.get("token");
  const { isLoading, isError, data, error, refetch } = useQuery(
    fetchApi, {
      enabled: !!token,
      onError: (error) => {
  return { isLoading, isError, data, error, refetch };
export { useApiQuery };

The useApiQuery hook uses the useQuery hook from React Query to handle the data fetching. It takes an array of dependencies, in this case [GET_API_NAME], to identify the query. Whenever the dependencies change, React Query will automatically re-fetch the data. The fetchApi function we defined earlier is passed as the second argument.

The enabled option is set to !!token to control whether the query should be enabled based on the presence of the authentication token. If there is no token available, the query will not be executed.

The onError option allows us to handle any errors that occur during the query. In this case, we simply log the error to the console, but you can customize the error handling as per your requirements.

The hook returns an object containing various values: isLoading indicates whether the data is currently being fetched, isError indicates if an error occurred, data contains the fetched data, error holds the error object if any, and refetch is a function to manually trigger a data re-fetch.

Section 3: Setting up Axios and Authorization

To make API requests with authentication, we'll use Axios, a popular JavaScript library. Axios provides an easy-to-use API for sending HTTP requests and handling responses. Additionally, we'll configure Axios to include the authorization token in the request headers. Let's set it up.

First, install Axios and import the necessary dependencies:

jsxCopy codeimport axios from "axios";
import Cookies from "js-cookie";
import { getApiURL } from "./baseURL";

Next, create an instance of Axios using the axios.create method:

const client = axios.create({
  baseURL: getApiURL(),

The baseURL is set using the getApiURL function, which should return the URL of your API.

Now, let's define a function called setAuthorizationHeader:

export const setAuthorizationHeader = () => {
  const token = Cookies.get("token");
  if (token) {
    client.defaults.headers.common["Authorization"] = `Bearer ${token}`;
  } else {
    delete client.defaults.headers.common["Authorization"];

The setAuthorizationHeader function retrieves the authentication token from cookies using Cookies.get. If a token is available, it sets the Authorization header in the Axios client to include the token. If there is no token, the Authorization header is deleted.

To initialize the authorization header, call setAuthorizationHeader:


Additionally, we can add an interceptor to update the authorization header before each request:

client.interceptors.request.use((config) => {
  return config;

The interceptor calls setAuthorizationHeader to ensure that the latest token is included in the request headers.

Finally, we can define a request function to handle sending requests:

export const request = ({ ...options }) => {
  const onSuccess = (response) => {
    return response;
  const onError = (error) => {
    return error;
  return client(options).then(onSuccess).catch(onError);

The request function takes an options object and sends the request using the Axios client. It returns a promise that resolves with the response data on success or rejects with an error on failure.

Section 4: Usage

Now that we have our custom hook useUsers set up, let's see how we can use it in a React component. We'll show an example of accessing the data, isLoading, and refetch properties returned by the useApiQuery hook.

const { data, isLoading, refetch } = useApiQuery();

If the data is available, we can map over the data array and render a list item for each item in the data if it's an array.


In this blog post, we learned how to build a custom hook using React Query for data fetching and Axios for handling API requests and authentication. By combining these powerful libraries, we can create efficient and reusable code for managing API calls in our React applications.

Feel free to customize and expand upon the code snippets provided to fit your specific use case.

If you found this blog post helpful, feel free to follow me on Twitter @thedeepanshuweb, connect with me on LinkedIn Deepanshu Goel