I am basically trying to save the state of like/dislike on list of products which I am trying to fetch from an API using axios, but I'm getting the below error.
A non-serializable value was detected in the state, in the path: 'products. Value: {"_x":0"_y",_z":null,"_A":null}
To save the state, I am trying to use Redux Toolkit. Below I have codes for productSlice
component and ProductListScreen
component.
productSlice.js
import { createSlice } from "@reduxjs/toolkit";
import axios from "axios";
const productsSlice = createSlice({
name: "products",
initialState: { items: [], likes: [] },
reducers: {
fetchProducts: async (state) => {
const response = await axios.get("https://dummyjson.com/products");
state.items = response.data;
state.likes = new Array(state.items.length).fill(false);
},
toggleLike: (state, action) => {
state.likes[action.payload.index] = action.payload.isLiked;
},
},
});
export const { fetchProducts, toggleLike } = productsSlice.actions;
export default productsSlice.reducer;
productListScreen.js
import { useEffect, useState } from "react";
import { FlatList, Text, View } from "react-native";
import { useDispatch, useSelector } from "react-redux";
import { fetchProducts, toggleLike } from "./productsSlice";
const ProductListScreen = () => {
const products = useSelector((state) => state.products.items);
const likes = useSelector((state) => state.products.likes);
const dispatch = useDispatch();
useEffect(() => {
dispatch(fetchProducts());
}, []);
const handleLike = (index, isLiked) => {
dispatch(toggleLike({ index, isLiked }));
};
const renderItem = ({ item, index }) => (
<View>
<Text>{item.title}</Text>
<LikeDislikeButton
productId={item.id}
liked={likes[index]}
onPress={() => handleLike(index, !likes[index])}
/>
</View>
);
return (
<View>
<FlatList
data={products}
renderItem={renderItem}
keyExtractor={(item) => item.id}
/>
</View>
);
};
export default ProductListScreen;
CodePudding user response:
Reducer functions are supposed to be pure synchronous functions. You have declared the fetchProducts
reducer function async
which implicitly returns a Promise object. This is the non-serializable object that is stored into state.products
.
You should be creating and using an asynchronous action, i.e. a Thunk, to make asynchronous API calls. Refactor fetchProducts
to be an asynchronous action. Use the productSlice
's extraReducers
to handle the fulfilled Promise returned from the fetchProducts
thunk.
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
import axios from "axios";
export const fetchProducts = createAsyncThunk(
"products/fetchProducts",
async () => {
const response = await axios.get("https://dummyjson.com/products");
return response.data;
},
);
const productsSlice = createSlice({
name: "products",
initialState: { items: [], likes: [] },
reducers: {
toggleLike: (state, action) => {
state.likes[action.payload.index] = action.payload.isLiked;
},
},
extraReducers: builder => {
builder
.addCase(fetchProducts.fulfilled, (state, action) => {
const { products } = action.payload;
state.items = products;
state.likes = new Array(products.length).fill(false);
});
},
});
export const { toggleLike } = productsSlice.actions;
export default productsSlice.reducer;
CodePudding user response:
response.data
is the object that contains the list of products.
{"products":[{"id":1,"title":"iPhone 9",...}]}
const response = await axios.get("https://dummyjson.com/products");
state.items = response.data.products;