Home > Software design >  Extra reducer not catching error from Axios async request with redux Thunk
Extra reducer not catching error from Axios async request with redux Thunk

Time:01-08

I'm doing a simple request to a server and it works. I manipulated to url to make sure the error was also managed correctly, but it doesn't work. Although the thunk I created does catch the error, the case rejected never gets triggered in the extra reducer. I'm not sure what could be the issue. see below this reducer:

import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import axios, { AxiosError } from "axios";

const baseURL = "https://....";

// Fetches all items from Server
export const getTravelItems = createAsyncThunk("items/fetchItems", async () => {
  try {
    const responseItems = await axios.get(`${baseURL}/items.js`);
    return responseItems.data;
  } catch (_err) {
    const error = _err as AxiosError;
    return error.message;
  }
});

interface state {
  reqStatus: "idle" | "pending" | "succeeded" | "failed";
  travelItems: { itemName: string }[];
  error: null | string | undefined;
}

const initialState: state = {
  reqStatus: "idle",
  travelItems: [],
  error: null,
};

const itemsSlice = createSlice({
  name: "items",
  initialState,
  reducers: {},
  extraReducers: (builder) => {
    builder
      .addCase(getTravelItems.pending, (state) => {
        state.reqStatus = "pending";
      })
      .addCase(getTravelItems.fulfilled, (state, action) => {
        //  Modelling data before I update the state
        const fetchedItems = [];
        for (let item in action.payload) {
          fetchedItems.push({
            ...action.payload[item],
            id: item,
          });
        }
        state.reqStatus = "succeeded";
        state.travelItems = fetchedItems;
      })
      .addCase(getTravelItems.rejected, (state, payload) => {
        console.log(payload.error);
        console.log("error! ");
        state.reqStatus = "failed";
        state.error = payload.error.message;
      });
  },
});

export default itemsSlice.reducer;

The component where I consume the data is as follow:

import React, { useEffect } from "react";
import { useAppDispatch, useAppSelector } from "./store/storeHooks";

import { ThemeProvider } from "@mui/material/styles";


// components for UI
import Header from "./ui/components/navigation/header";

//items
import { getTravelItems } from "./store/reducers/getItemsReducer";

const App: React.FC = () => {

  const dispatch = useAppDispatch();
  // state
  const { reqStatus, error, travelItems } = useAppSelector(
    (state) => state.getItemsReducer
  );

  useEffect(() => {
    if (reqStatus === "idle") {
      dispatch(getTravelItems());
    }
  }, [reqStatus, dispatch]);

  let travelItemsElements;

  switch (reqStatus) {
    case "pending":
      travelItemsElements = <p>Loading</p>;
      break;
    case "succeeded":
      travelItemsElements = travelItems.map((item, i: number) => (
        <p key={i}>{item.itemName}</p>
      ));
      break;
    case "failed":
      travelItemsElements = <p>{error}</p>;
      break;
    default:
      travelItemsElements = null;
  }

  return (
    <ThemeProvider theme={theme}>
      <Header />
      <Box>{travelItemsElements}</Box>
    </ThemeProvider>
  );
};

export default App;

CodePudding user response:

try to use rejectWithValue:

export const getTravelItems = createAsyncThunk("items/fetchItems", async (_, { rejectWithValue }) => {
  try {
    const responseItems = await axios.get(`${baseURL}/items.js`);
    return responseItems.data;
  } catch (_err) {
    const error = _err as AxiosError;
    return rejectWithValue({ data: error.message  });
  }
});
  • Related