Vaikruta
Vaikruta

Reputation: 301

RTK Query and createSlice extra reducers

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.

Upvotes: 9

Views: 6574

Answers (2)

OLUWAFEMI SOSANYA
OLUWAFEMI SOSANYA

Reputation: 31

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

Upvotes: 3

JoyShaheb
JoyShaheb

Reputation: 568

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()

Upvotes: 3

Related Questions