RTK Query and createSlice extra reducers
Asked Answered
B

2

9

I'm new to RTK query, I'm currently watching a tutorial wherein the RTK query data is stored in a redux slice using ExtraReducers. I'm trying to store RTK query data in a slice state, but unable to do so.

import { createSlice } from "@reduxjs/toolkit";
import apiService from "../Services/serviceFeature";

const initialState = {
  userInfo: null,
};

const userSlice = createSlice({
  name: "user",
  initialState,
  reducers: {
    userLogout: (state, action) => initialState,
  },
  extraReducers: (builder) => {
    builder.addMatcher(
      apiService.endpoints.authRegister.matchFulfilled,
      (state, action) => (state.userInfo = action.payload)
    );
    builder.addMatcher(
      apiService.endpoints.authLogin.matchFulfilled,
      (state, action) => (state.userInfo = action.payload)
    );
  },
});

export const { userLogout } = userSlice.actions;

export default userSlice.reducer;


No matter what I do, the state does not get updated with the payload value and the userInfo in the state remains null throughout.

If I write the logic like this, everything magically works fine and the slice stores the value from RTK query.

import { createSlice } from "@reduxjs/toolkit";
import apiService from "../Services/serviceFeature";

const initialState = null;

const userSlice = createSlice({
  name: "user",
  initialState,
  reducers: {
    userLogout: (state, action) => initialState,
  },
  extraReducers: (builder) => {
    builder.addMatcher(
      apiService.endpoints.authRegister.matchFulfilled,
      (_, action) => action.payload
    );
    builder.addMatcher(
      apiService.endpoints.authLogin.matchFulfilled,
      (_, action) => action.payload
    );
  },
});

export const { userLogout } = userSlice.actions;

export default userSlice.reducer;


The slice doesn't store any information if I mention state in extraReducers i.e (state,action).The devtools says apiService/executeMutation/pending throughout and the state never gets updated. Once I remove state and put in _ the request gets fullfilled and i get the data.

The slice stores the information If I write it as (_,action). Why does this happen? Any idea?

Edit: Dispatching action from the front end doesn't work as well.I tried defining an inital state in the slice and logged in(by using(_,action)).I get the result from the addMatcher and the slice gets updated with the new userInfo. While this happens the dev tools show no trace of the initial state I had defined. The dev tools just shows the user data without any state info(if in case the code is written in the latter fashion). Despite the initialState having userInfo( initialState:{userInfo:null}, devtools doesn't show it. Only the result of addMatcher is shown(it's as if the initial state doesn't exist at all)

Image 1- prod slice enter image description here

Despite the initialState having products:[], and name:'', it appears to have disappeared in redux Dev tools and instead I only get the name of the slice and the api result(from the addMatcher)

enter image description here

This is the RTK query code

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

const apiService = createApi({
  reducerPath: "fakeStore",
  baseQuery: fetchBaseQuery({ baseUrl: "https://fakestoreapi.com/" }),
  endpoints: (builder) => ({
    getProd: builder.query({
      query: () => ({
        url: "products",
        method: "GET",
      }),
    }),
  }),
});

export default apiService;

export const { useGetProdQuery } = apiService;

Store

import { configureStore } from "@reduxjs/toolkit";
import prodReducer from "./prodSlice";
import apiService from "./service";

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

The problem is that I cannot update the state in the slice by saying state.products=action.payloadif I include addMatcher(since, the initialState disappears, and the addMatcher stays at loading forever).If I simply say (state,action)=>action.payload the entire initialState disappears and I get the api value from the add matcher.

Blond answered 11/12, 2022 at 4:7 Comment(4)
That first version seems okay. Do you get any errors in the browser console?Entreat
No errors. I tried doing everything from the beginning but the same thing repeats. The dev tools show the name of the reducer and the value(from the extraReducer), the initialState disappears completely. The devl tools show user:[{}...{}] without any trace of userInfo in the initialState.Blond
All I could think of at this point would be a typo somewhere in initialState :/Entreat
I edited out the post attaching images, please do tell me what I'm doing wrong.Blond
S
3

What you are missing is the isAnyOf() which is a higher-order function that returns a function that may be used to check whether an action matches any one of the supplied type guards or action creators. you can update your code as

import { createSlice, isAnyOf } from "@reduxjs/toolkit";
import apiService from "../Services/serviceFeature";

const initialState = {
  userInfo: null,
};

const userSlice = createSlice({
  name: "user",
  initialState,
  reducers: {
    userLogout: (state, action) => initialState,
  },
  extraReducers: (builder) => {
    builder.addMatcher(
      isAnyOf(apiService.endpoints.authRegister.matchFulfilled), //updated
      (state, action) => (state.userInfo = action.payload)
    );
    builder.addMatcher(
      isAnyOf(apiService.endpoints.authLogin.matchFulfilled), //updated
      (state, action) => (state.userInfo = action.payload)
    );
  },
});

export const { userLogout } = userSlice.actions;

export default userSlice.reducer;

check this rtk-query example from the docs for more insights on usage

Showery answered 29/9, 2023 at 21:53 Comment(0)
T
2

you don't have to store data from rtk query to anywhere. you simply import the useGetProdQuery in the component and use it like this

const {data, isLoading, isFetching, error} = useGetProdQuery()

Tazza answered 1/1, 2023 at 6:22 Comment(1)
Not 100% true (well maybe in this case). But in a case where you would want to persist the data to another reducer then you would use extraReducers to save data once a request through RTK Query is completed.Tuba

© 2022 - 2024 — McMap. All rights reserved.