Search code examples
reactjsreduxaxiosredux-toolkit

Can I access state inside a createAsyncThunk w/axios with redux toolkit?


I'm fairly new to redux toolkit so I'm still having a few issues with it!

As per the code below, I'm trying to access state (loginDetails.username and loginDetails.password) inside my createAsyncThunk. I'm obviously doing something wrong here - I've tried writing the createAsyncThunk function inside a different file, attempting to access the state inside that file and then importing the function, but either way it's failing.

// Import: Packages
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import axios from "axios";

// AsyncThunk: getUserDetails
export const getUserDetails = createAsyncThunk(
  "userDetails/getUserDetails",
  async () => {
    try {
      const apiUrl = process.env.REACT_APP_URL;

      var config = {
        method: "get",
        url: `${apiUrl}/claimSet?UserName=${state.loginDetails.username}&Password=${state.loginDetails.password}`,
        headers: {
          accept: "application/json",
        },
      };

      const response = await axios(config);
      const data = await response.data;
      return data;
    } catch (error) {
      console.log(error);
    }
  }
);

// Slice: userDetailsSlice
export const userDetailsSlice = createSlice({
  name: "userDetails",
  initialState: {
    loginDetails: {
      username: "",
      password: "",
    },
    details: [],
    status: null,
  },
  reducers: {
    addUsername: (state, { payload }) => {
      state.loginDetails.username = payload;
    },
    addPassword: (state, { payload }) => {
      state.loginDetails.password = payload;
    },
  },
  extraReducers: {
    [getUserDetails.pending]: (state, action) => {
      state.status = "loading";
    },
    [getUserDetails.fulfilled]: (state, { payload }) => {
      state.details = payload;
      state.status = "success";
    },
    [getUserDetails.rejected]: (state, action) => {
      state.status = "failed";
    },
  },
});

// Actions: addUsername, addPassword
export const { addUsername, addPassword } = userDetailsSlice.actions;

// Reducer: userDetailsSlice.reducer
export default userDetailsSlice.reducer;

The code in the config url ${state.loginDetails.username}, etc. is just one of many failed attempts to get hold of the state. I understand that part of the issue is that the createAsyncThunk is declared before the state/slide is below, but I still can't seem to find a way around it.

Any help would be really appreciated!

Thanks in advance <3


Solution

  • The async function consumes a "payload" argument, and secondly a thunkAPI object that contains a getState method.

    payloadCreator

    thunkAPI: an object containing all of the parameters that are normally passed to a Redux thunk function, as well as additional options:

    • dispatch: the Redux store dispatch method
    • getState: the Redux store getState method
    • extra: the "extra argument" given to the thunk middleware on setup, if available
    • requestId: a unique string ID value that was automatically generated to identify this request sequence
    • signal: an AbortController.signal object that may be used to see if another part of the app logic has marked this request as needing cancelation.
    • rejectWithValue: rejectWithValue is a utility function that you can return in your action creator to return a rejected response with a defined payload. It will pass whatever value you give it and return it in the payload of the rejected action.
    // AsyncThunk: getUserDetails
    export const getUserDetails = createAsyncThunk(
      "userDetails/getUserDetails",
      async (arg, { getState }) => { // <-- destructure getState method
        const state = getState(); // <-- invoke and access state object
        try {
          const apiUrl = process.env.REACT_APP_URL;
    
          var config = {
            method: "get",
            url: `${apiUrl}/claimSet?UserName=${state.loginDetails.username}&Password=${state.loginDetails.password}`,
            headers: {
              accept: "application/json",
            },
          };
    
          const response = await axios(config);
          const data = await response.data;
          return data;
        } catch (error) {
          console.log(error);
        }
      }
    );