DEV Community

Cover image for Learn RTK Query in Next.js in 5 Minutes 🚀
Subham
Subham

Posted on

Learn RTK Query in Next.js in 5 Minutes 🚀

RTK Query is a powerful data fetching and caching tool that is part of the Redux Toolkit package. It lets you define your API endpoints as functions, and then automatically generates React hooks to fetch and update data from those endpoints. It also handles loading states, caching, invalidation, and more. 🙌

In this blog, you will learn how to use RTK Query in a Next.js app. You will see how easy it is to set up your store and API service, how to use the generated hooks in your components, and how to customize your queries and mutations. 💯

By the end of this blog, you will be able to use RTK Query in your own Next.js projects and enjoy the benefits of data fetching and caching done right. 🔥

So, are you ready to learn more about RTK Query? Let's get started! 😊

You can Check the Code Here: https://github.com/Subham-Maity/rtk_query

  1. Syntax Check out the docs
// Import the createApi and fetchBaseQuery functions from the RTK Query library
import {createApi, fetchBaseQuery} from "@reduxjs/toolkit/query/react";

// Create an API service using the createApi function
export const productsAPI = createApi({
    // Specify a unique name for the API slice in the Redux store
    reducerPath: "productsAPI",
    // Specify a base query function that will be used to make network requests
    // In this case, we use the fetchBaseQuery function that is a wrapper around the native fetch API
    baseQuery: fetchBaseQuery({
        // Specify the base URL for the API endpoints
        baseUrl: "",
    }),
    // Define the endpoints for the API service using a builder callback
    // The builder provides methods for defining query and mutation endpoints
    endpoints: (builder) => ({}),
});

// Export the auto-generated hooks for the defined endpoints
// The hooks allow us to easily perform queries and mutations in our React components
export const {} = productsAPI;

Enter fullscreen mode Exit fullscreen mode
  1. Inside the endpoints callback, we can define our endpoints using the builder object. The builder object provides methods for defining query and mutation endpoints.
//here getProductByName is the name of the endpoint and builder.query is the method to define query endpoints and query is the callback function that will be called when the endpoint is used.
getProductByName: builder.query({
    query: () => ``,
})
Enter fullscreen mode Exit fullscreen mode
//here useGetProductByNameQuery is the name of the hook that will be used to call the endpoint 
// syntax: use + endpoint name(First letter capital) + Query
export const {useGetProductByNameQuery} = productsAPI;
Enter fullscreen mode Exit fullscreen mode

final

import {createApi, fetchBaseQuery} from "@reduxjs/toolkit/query/react";

export const productsAPI = createApi({
    reducerPath: "productsAPI",
    baseQuery: fetchBaseQuery({
        baseUrl: "",
    }),
    endpoints: (builder) => ({
        getProductByName: builder.query({
            query: () => ``,
        }),
    }),
});

export const {useGetProductByNameQuery} = productsAPI;

Enter fullscreen mode Exit fullscreen mode
  1. Define the base URL for the API endpoints
//this will be the base url for the endpoints
baseUrl: "https://jsonplaceholder.typicode.com"
Enter fullscreen mode Exit fullscreen mode
//This will be the endpoint
query: () => `users`
Enter fullscreen mode Exit fullscreen mode

final

import {createApi, fetchBaseQuery} from "@reduxjs/toolkit/query/react";

export const productsAPI = createApi({
    reducerPath: "productsAPI",
    baseQuery: fetchBaseQuery({
        baseUrl: "https://jsonplaceholder.typicode.com",
    }),
    endpoints: (builder) => ({
        getProductByName: builder.query({
            query: () => `users`,
        }),
    }),
});

export const {useGetProductByNameQuery} = productsAPI;
Enter fullscreen mode Exit fullscreen mode
  1. Create store and use it in the provider then wrap the layout with the provider
import {configureStore} from "@reduxjs/toolkit";

export const store = configureStore({
    reducer: {},
});
Enter fullscreen mode Exit fullscreen mode

ReduxProvider.tsx

"use client";
import React from "react";

import {store} from "../store";
/* Core */
import {Provider} from "react-redux";

/* Instruments */

export const ReduxProvider = (props: React.PropsWithChildren) => {
    return <Provider store={store}>{props.children}</Provider>;
};

Enter fullscreen mode Exit fullscreen mode





```tsx
import "./globals.css";
import type {Metadata} from "next";
import {Inter} from "next/font/google";
import React from "react";
import {ReduxProvider} from "@/redux/Provider/ReduxProvider";

const inter = Inter({subsets: ["latin"]});

export const metadata: Metadata = {
    title: "Create Next App",
    description: "Generated by create next app",
};

export default function RootLayout({
                                       children,
                                   }: {
    children: React.ReactNode;
}) {
    return (
        <html lang="en">
        <ReduxProvider>
            <body className={inter.className}>{children}</body>
        </ReduxProvider>
        </html>
    );
}
Enter fullscreen mode Exit fullscreen mode
  1. Inside the store reducer add the api reducer
//Generate the reducer as a specific top-level key in the store
[productsAPI.reducerPath]
:
productsAPI.reducer
Enter fullscreen mode Exit fullscreen mode

final

//store.ts
import {configureStore} from "@reduxjs/toolkit";
import {productsAPI} from "@/redux/slice/api";

export const store = configureStore({
    reducer: {
        [productsAPI.reducerPath]: productsAPI.reducer,
    },
});
Enter fullscreen mode Exit fullscreen mode
  1. After the reducer use the middleware
// Adding the api middleware enables caching, invalidation, polling,and other useful features of `rtk-query`.
middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware().concat(productsAPI.middleware)
Enter fullscreen mode Exit fullscreen mode
setupListeners(store.dispatch);
Enter fullscreen mode Exit fullscreen mode
// takes an optional callback as the 2nd arg for customization
setupListeners(store.dispatch);
Enter fullscreen mode Exit fullscreen mode

final

//store.ts
import {configureStore} from "@reduxjs/toolkit";
import {productsAPI} from "@/redux/slice/api";

export const store = configureStore({
    reducer: {
        [productsAPI.reducerPath]: productsAPI.reducer,
    },
    middleware: (getDefaultMiddleware) =>
        getDefaultMiddleware().concat(productsAPI.middleware),
});
setupListeners(store.dispatch);
Enter fullscreen mode Exit fullscreen mode
  1. Now we can use the hook in our component

Open page.tsx

//Once a service has been defined, you can import the hooks to make a request.
const data = useGetProductByNameQuery("");
console.log(data);
Enter fullscreen mode Exit fullscreen mode

Now destruct the data and use it in the component

const {data} = useGetProductByNameQuery("");
console.log(data);
Enter fullscreen mode Exit fullscreen mode

You can see the data in the console of the browser
page.tsx

"use client";

import {useGetProductByNameQuery} from "@/redux/slice/api";

export default function Home() {
    const {data} = useGetProductByNameQuery("");

    return (
        <main>
            <h1>Home</h1>
            <p>rtk-query data: {JSON.stringify(data)}</p>
        </main>
    );
}

Enter fullscreen mode Exit fullscreen mode
  1. Now you can iterate over the data and show it in the component

make a type.ts

// types.ts
export interface UserData {
    id: number;
    name: string;
    username: string;
    email: string;
    address: {
        street: string;
        suite: string;
        city: string;
        zipcode: string;
        geo: {
            lat: string;
            lng: string;
        };
    };
    phone: string;
    website: string;
    company: {
        name: string;
        catchPhrase: string;
        bs: string;
    };
}
Enter fullscreen mode Exit fullscreen mode
"use client";

import {useGetProductByNameQuery} from "@/redux/slice/api";
import {UserData} from "@/app/types";

export default function Home() {
    const {data} = useGetProductByNameQuery("");
    //usually happens when the API call hasn't finished fetching the data yet
    //To resolve this issue, you need to ensure that you're handling the loading state correctly. One way to do this is by checking whether the data is present before trying to map over it. 
    if (!data) {
        return <div>Loading...</div>;
    }
    return (
        <div>
            {data.map((item: UserData) => (
                <div key={item.id}>
                    <h2>{item.name}</h2>
                    <p>{item.email}</p>
                    <p>{item.company.catchPhrase}</p>
                    <p>{item.address.city}</p>
                </div>
            ))}
        </div>);
}
Enter fullscreen mode Exit fullscreen mode

Check out the preview here

If you want to see more of my work, you can follow me on LinkedIn, GitHub, and Twitter. I post regularly about web development, data fetching, and other topics. 🚀

Thank you for reading this blog and stay tuned for more. If you have any questions or feedback, feel free to leave a comment below or contact me directly. I would love to hear from you. 🙌

If you are looking for a freelance web developer who can help you with your projects, you can also contact me. I have experience in working with Next.js, RTK Query, and other modern web technologies. I can help you build fast, scalable, and user-friendly web applications. 💯

You can reach me by sending an email to codexam.personal@gmail.com or by filling out this [contact form]. I will get back to you as soon as possible. 😊

I look forward to hearing from you and collaborating with you on your projects. 🙌

Until next time, happy coding! 👋

Top comments (1)

Collapse
 
onifaie profile image
Abo_Majed

thanks good jop broth