How to Set Up Redux Toolkit Query

Redux Toolkit Query is an add-on for Redux Toolkit that provides a powerful data fetching and caching tool. It handles most of the heavy lifting for us, so we don't have to write the fetching and caching mechanisms from scratch.

Setting up the Rexux Toolkit Query API

npm create vite@latest

Create a new React project using Vite or another tool. If you are using Vite, run the command above, then navigate to the project folder in your terminal and run npm i.

npm install @reduxjs/toolkit

Run the above command to install ReduxJS Toolkit.

Creating Our Redux Store and API

Inside your src directory, create a new folder named store. Inside this folder, create a new file called index.js. Next, create another folder named api inside the store folder. Then create a file pokemonApi.js.

// store/api/pokemonApi.js
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";

const pokemonApi = createApi({
  reducerPath: "pokemon",
  baseQuery: fetchBaseQuery({
    baseUrl: "https://pokeapi.co/api/v2/",
  }),
  endpoints(builder) {
    return {
      fetchPokemons: builder.query({
        // GET Requests are read and therefore query
        query: (pokemonName) => {
          return {
            url: "/pokemon",
            pokemonName: pokemonName,
            method: "GET",
          };
        },
      }),
    };
  },
});

export { pokemonApi };
export const { useFetchPokemonsQuery } = pokemonApi;

There is a lot of setup needed for this to work, so let's get started right away. Inside pokemonApi.js, import createApi from @reduxjs/toolkit/query/react. Note the "react" part after "query" in the import; don't miss it. If you use just @reduxjs/toolkit/query, it won't work. This mistake happens often.

Next, let's create pokemonApi by assigning it the createApi function. The createApi function will primarily take three parameters:

  • reducerPath: This will be used inside the configureStore later. It tells the store what name to use for the state.

  • baseQuery: This is where we provide the API URL to make requests.

  • endpoints: All sorts of requests we make for this particular baseUrl come here, whether they are GET requests or POST requests.

The reducerPath will take a string; here, we use "pokemon". For baseQuery, import fetchBaseQuery from @reduxjs/toolkit/query/react. In that function, add an object with the baseUrl property set to your API URL.

The endpoint is where we will make configuration for all sorts of requests. There are two types query and mutation. Here, we are making a query request. The difference is that query is for reading the data only and mutation is for modifying the data. Let us now take a look at this endpoint function and what it is doing.

// This is just for reference.
 endpoints(builder) {
    return {
      fetchPokemons: builder.query({
        // GET Requests are read and therefore query
        query: (pokemonName) => {
          return {
            url: `/pokemon/${pokemonName}`,
            method: "GET",
          };
        },
      }),
    };
  },

As you can see, we are returning an object inside this endpoints function with the configuration. The name fetchPokemons is what you will provide, depending on what you are doing. This name is very important because RTK Query (Redux Toolkit Query) uses it to create a function that we will call to make requests to the API. This becomes use + FetchPokemons + Query, so it will be like useFetchPokemonsQuery for the actual function. We will see how to call this later. If it was fetchDigimon, then it would become useFetchDigimonQuery. You get the idea.

The fetchPokemons function uses builder.query, which takes an object with a query property. This property takes a function with a parameter we provide, pokemonName. This is what you will use when making a request to this URL. The url inside the return object will be appended to the base URL given above. So, https://pokeapi.co/api/v2/ will become https://pokeapi.co/api/v2/pokemon/, and the pokemonName property is a variable we pass after that. So, it will become https://pokeapi.co/api/v2/pokemon/${pokemonName}.

As I mentioned above, useFetchPokemonsQuery when called with "ditto" for example will make the URL https://pokeapi.co/api/v2/pokemon/ditto.

Configuring the Store for RTK Query

// store/index.js
import { configureStore } from "@reduxjs/toolkit";
import { pokemonApi } from "./api/pokemonApi";
import { setupListeners } from "@reduxjs/toolkit/query";

const store = configureStore({
  reducer: {
    [pokemonApi.reducerPath]: pokemonApi.reducer,
  },
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware().concat(pokemonApi.middleware),
});

setupListeners(store.dispatch);
export { store };

Inside your src/store/index.js file, import configureStore from Redux Toolkit and the pokemonApi we created earlier. The configureStore function takes an object with a reducer property. Here, we add all the reducers from slices or RTK Queries. You can use both in a single project.

In the reducer, you might notice a strange syntax [pokemonApi.reducerPath]: pokemonApi.reducer. What does this mean? We are not creating an array; instead, we are saying that the reducerPath we defined earlier in pokemonApi will be the key here. So, it is the same as pokemon: pokemonApi.reducer. Let me give you an example to understand this syntax.

// Example
const text = {
    type : "strong"
}

const arial = {
    [text.type]: "hello!"
}

console.log(arial.strong) // Prints "hello!"

So, basically, we are doing the same thing. The pokemonApi.reducerPath becomes the key, which is "pokemon" in this case.

Lastly, we add some setup code that will essentially stay the same. Adding the API middleware enables caching, invalidation, polling, and other useful features of RTK Query.

Finally, we add setupListeners, which is optional but required for refetchOnFocus/refetchOnReconnect behaviors. You need to add an import statement above to import setupListeners from @reduxjs/toolkit/query.

Using the RTK Query inside App

// src/App.jsx
import "./App.css";
import { useFetchPokemonsQuery } from "./store/api/pokemonApi";

function App() {
  const { data, isLoading } = useFetchPokemonsQuery("ditto");
  console.log(data, isLoading);

// Render the data here...
  return <></>;
}

export default App;

Lastly, we import the useFetchPokemonsQuery from our pokemonApi file inside App.jsx and call it with a Pokémon name. Notice that we don't need to use any useEffect lifecycle methods. RTK Query handles that for us. You can render the data you get back and add a condition to display a loader when it is fetching data, which is when isLoading becomes true.

Thank you for reading! I hope this helped you understand the Redux Toolkit Query setup better.

0
Subscribe to my newsletter

Read articles from Shiwanshu Shubham directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Shiwanshu Shubham
Shiwanshu Shubham

Hey there, I'm Shiwanshu, a passionate frontend developer and designer hailing from India. With proficiency in NextJS, ReactJS, CSS3, HTML5, Figma, UI Design, and Typescript, I've embarked on a journey into the tech space. This blog is a documentation of my progress as I delve deeper into the world of technology.