Home > Software design >  RTK query - I am clearly calling one query but for some reason a different one is being actioned
RTK query - I am clearly calling one query but for some reason a different one is being actioned

Time:10-15

As the title says. This is extremely bizarre to me.

I am quite clearly calling the getThisCategory(genre) query from categoriesApi.js, which should be:

'https://kitsu.io/api/edge/anime?filter[categories]=${genre}'

but in my console there is an error that says:

"GET https://kitsu.io/api/edge/Vampire/anime?limit=20 404".

This looks to me like the query from the animeApi.js file, with the genre parameter passed in. I have no idea why it is calling this query instead.

Please can someone help, this is really frustrating.

Files below:

animeApi.js (the query that SHOULDN'T be getting called but is):

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

const animeApiHeaders = {
    "Accept": "application/vnd.api json",
    "Content-Type": "application/vnd.api json",
};

const baseUrl = 'https://kitsu.io/api/edge';

const createRequest = (url) => ({ url, headers: animeApiHeaders });

export const animeApi = createApi({
    reducerPath: 'animeApi',
    baseQuery: fetchBaseQuery({ baseUrl }),
    endpoints: (builder) => ({
        getCategoryOfAnime: builder.query({
            query: (category) =>
                createRequest(`/${category}/anime?limit=20`)
        }),
    })
});

export const { useGetCategoryOfAnimeQuery } = animeApi;

categoriesApi.js (the query that SHOULD be getting called):

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

const categoryHeaders = {
    "Accept": "application/vnd.api json",
    "Content-Type": "application/vnd.api json",
};

const baseUrl = 'https://kitsu.io/api/edge';

const createRequest = (url) => ({ url, headers: categoryHeaders });

export const categoriesApi = createApi({
    reducerPath: 'categoriesApi',
    baseQuery: fetchBaseQuery({ baseUrl }),
    endpoints: (builder) => ({
        getAllCategories: builder.query({
            query: () => 
                createRequest(`/categories?page[limit]=40`)
        }),
        getThisCategory: builder.query({
            query: (genre) =>
                createRequest(`/anime?filter[categories]=${genre}`)
        }),
    })
});

export const { useGetAllCategoriesQuery, useGetThisCategoryQuery } = categoriesApi;

GenrePage.js (only the relevant parts of component):

import React, { useState, useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { Link, useParams } from 'react-router-dom';
import { useGetThisCategoryQuery } from '../../services/categoriesApi';
import { addThisCategory } from './GenrePageSlice';
import CircularProgress from "@mui/material/CircularProgress";
import './GenrePage.css';
import AnimeCard from '../AnimeCard/AnimeCard';

const GenrePage = () => {
    
    const { genre } = useParams();
    const dispatch = useDispatch();
    const genreData = useSelector((state) => state.genrePage.thisCategory);
    const { data: thisCategory, isFetching } = useGetThisCategoryQuery(genre);

    useEffect(() => {
        dispatch(addThisCategory(thisCategory));
    }, [thisCategory]);

store.js:

import { combineReducers, configureStore } from "@reduxjs/toolkit";

import { animeApi } from "../services/animeApi";
import { categoriesApi } from "../services/categoriesApi";

import animeBannerReducer from '../components/AnimeBanner/AnimeBannerSlice';
import animeCategoryReducer from "../components/AnimeCategoryPage/AnimeCategoryPageSlice";
import categoriesReducer from '../components/Categories/CategoriesSlice';

export default configureStore({
    reducer: {
        [animeApi.reducerPath]: animeApi.reducer,
        [categoriesApi.reducerPath]: categoriesApi.reducer,
        animeBanner: animeBannerReducer,
        animeCategory: animeCategoryReducer,
        categories: categoriesReducer,
    },
    middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware().concat(animeApi.middleware, categoriesApi.middleware),
});

App.js:

import React, { useState } from 'react';
import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';

import "./App.css"

import Header from '../components/Header/Header';
import Homepage from '../components/Homepage/Homepage';
import AnimeCategoryPage from '../components/AnimeCategoryPage/AnimeCategoryPage';
import GenrePage from '../components/GenrePage/GenrePage';

const App = () => {

  return (
    <BrowserRouter>
        <div className="app">
          <Header />
          <Routes>
            <Route path="/" element={<Homepage />} />
            <Route path="/anime/:category" element={<AnimeCategoryPage />} />
            <Route path="/anime/:genre" element={<GenrePage />} />
          </Routes>
        </div>
    </BrowserRouter>

  );
};

export default App;

CodePudding user response:

A bit off-topic, but important enough to put it into an answer to this - in the hopes that someone else will read it in the future too:

Please do not use that kind of createRequest helper function.
That is taken from a tutorial that grossly misunderstands what baseQuery is for.

Essentially, baseQuery is already a createRequest function like this - the return value of an endpoint's query function will be passed as first argument into baseQuery, which will in the case of fetchBaseQuery then call fetch.

So please use fetchBaseQuery correctly instead here:

const baseUrl = 'https://kitsu.io/api/edge';

export const categoriesApi = createApi({
    reducerPath: 'categoriesApi',
    baseQuery: fetchBaseQuery({ 
      baseUrl,
//    either you can just set `headers` here:
//    headers: categoryHeader

//    or you use `prepareHeaders` where you can do some calulations and have access to stuff like `getState` or the endpoint name
      prepareHeaders: (headers, { getState, endpoint, type, forced }) => {
         headers.set("Accept", "application/vnd.api json")
         headers.set("Content-Type": "application/vnd.api json")
         return headers
      }
     }),
    endpoints: (builder) => ({
        getAllCategories: builder.query({
          query: () => { url: `/categories?page[limit]=40` }
// or the short notation: if you only have an `url` just pass a string
//        query: () => `/categories?page[limit]=40`
        }),
    })
});

Also, and that might also be a misconception from that tutorial: you should in almost all cases only have one api for your whole application. If you want to split that over multiple files, you can see the docs on Code Splitting

CodePudding user response:

Figured it out - I was being stupid.

The issue was with my routes set up in App.js.

Because the GenrePage was being called on the route '/anime/:genre', and the AnimeCategoryPage was being called on '/anime/:category', react-router was always calling the first component on the base '/anime' which was AnimeCategoryPage instead of GenrePage.

Fixed by changing the route for GenrePage to '/explore/:genre'

  • Related