There is a createAsyncThunk
in which I use axios
to make a request. If I do return res
, and I pass action.payload.data
to my pizzas array, then everything works, but I get an error in the console:
I understand what needs to be done (return res.data
) and then there will be no error.
But I need something to be returned return res
, because I need to get res.headers["x-total-count"]
from the request elsewhere and pass the quantity to itemsCount
export const fetchPizzas = createAsyncThunk("items/fetchPizzasStatus", async (params) => {
const { category, sortBy, order, search, perPage, currentPage } = params;
const res = await axios.get(`http://localhost:3001/items?${category}&q=${search}&_sort=${sortBy}&_order=${order}&_page=${currentPage}&_limit=${perPage}`);
return res;
});
const initialState = {
pizzas: [],
itemsCount: 0,
status: "loading",
};
export const getItemsSlice = createSlice({
name: "items",
initialState,
reducers: {},
extraReducers: {
[fetchPizzas.pending]: (state) => {
state.status = "loading";
state.pizzas = [];
},
[fetchPizzas.fulfilled]: (state, action) => {
state.status = "success";
state.pizzas = action.payload.data;
state.itemsCount = action.payload.headers["x-total-count"];
},
[fetchPizzas.rejected]: (state) => {
state.status = "error";
state.pizzas = [];
},
},
});
Assuming the API is configured to allow access to all the response headers then I'd suggest unpacking the header value you want/need in the action creator prior to returning a resolved value. The error is that something in the headers object is non-serializable, i.e. like a function.
Example:
export const fetchPizzas = createAsyncThunk(
"items/fetchPizzasStatus",
async ({ category, sortBy, order, search, perPage, currentPage }) => {
const { data, headers } = await axios.get(`http://localhost:3001/items?${category}&q=${search}&_sort=${sortBy}&_order=${order}&_page=${currentPage}&_limit=${perPage}`);
const itemCount = headers["x-total-count"];
return { data, itemCount };
}
);
const initialState = {
pizzas: [],
itemsCount: 0,
status: "loading",
};
export const getItemsSlice = createSlice({
name: "items",
initialState,
extraReducers: {
[fetchPizzas.pending]: (state) => {
state.status = "loading";
state.pizzas = [];
},
[fetchPizzas.fulfilled]: (state, action) => {
state.status = "success";
state.pizzas = action.payload.data;
state.itemsCount = action.payload.itemCount;
},
[fetchPizzas.rejected]: (state) => {
state.status = "error";
state.pizzas = [];
},
},
});
This said, it seems like the itemCount
state is simply the length of the pizzas
array and is easily derived from the existing state. It very likely doesn't need to also be stored in state. I'd recommend just completely removing it.
export const fetchPizzas = createAsyncThunk(
"items/fetchPizzasStatus",
async ({ category, sortBy, order, search, perPage, currentPage }) => {
const { data } = await axios.get(`http://localhost:3001/items?${category}&q=${search}&_sort=${sortBy}&_order=${order}&_page=${currentPage}&_limit=${perPage}`);
return data;
}
);
const initialState = {
pizzas: [],
status: "loading",
};
export const getItemsSlice = createSlice({
name: "items",
initialState,
extraReducers: {
[fetchPizzas.pending]: (state) => {
state.status = "loading";
state.pizzas = [];
},
[fetchPizzas.fulfilled]: (state, action) => {
state.status = "success";
state.pizzas = action.payload;
},
[fetchPizzas.rejected]: (state) => {
state.status = "error";
state.pizzas = [];
},
},
});
const pizzas = useSelector(state => state.items.pizzas);
const itemCount = useSelector(state => state.items.pizzas.length);