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 });
}
});