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.
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.