redux-toolkit -> non-serializable value detected
Asked Answered
P

3

7

Error:

index.js:1 A non-serializable value was detected in an action, in the path: payload.config.transformRequest.0.

Value: ƒ

transformRequest(data, headers) {

normalizeHeaderName(headers, 'Accept');
normalizeHeaderName(headers, 'Content-Type');

if (utils.isFormData(data) || utils.isArrayBuffer(data) || utils.i…

Slice:

export const getProducts = createAsyncThunk(
    'products/getProducts', 
    async() => {
        const res = await axios.get('http://localhost:5000/products/view-products', {withCredentials: true});
        return res;
    }
)

const getProductsSlice = createSlice({
    name : 'products',
    initialState : {
        list : [],
        status : null
    },
    extraReducers : {
        [getProducts.pending] : (state) => {
            state.status = 'loading'
        },
        [getProducts.fulfilled] : (state, {payload}) => {
            console.log("produtcts payload: ", payload.data)
            state.list = payload.data
            state.status = 'success'
        },
        [getProducts.rejected] : (state) => {
            state.status = 'failed'
        }
    }
})

Inside Component:

const dispatch = useDispatch();
    const data = useSelector(state => state.products.list);
    console.log("the products are :", data);

    useEffect(() => {
        dispatch(getProducts());
    }, [dispatch]);

Other slices in the app work fine. Having a hard time working around the non-serializable

Pharisaic answered 22/3, 2021 at 21:12 Comment(5)
return res; should be return res.data;Pavier
@NadiaChibrikova thanks, that solves it. Could you explain on it a bit like why does it give this^ error when the state is filled with payload.data anyway?Pharisaic
@NadiaChibrikova So if I need status code, what can I do?Salivate
@ehsan you need to construct a new object that will contain the fields you need, I assume it'll be data and status code, using the code above as example instead of return res you'll need to do something like return {data: res.data, status: res.status}Pavier
@NadiaChibrikova yes, nice solution. tnxSalivate
P
28

The problem with returning the result of axios.get as it is, is that apart from data it contains various other fields related to the request, including config for which you got the error. Although you're only saving data and not config, as the whole res object passes to the store it goes through a middleware called Serializability, which is included in redux-toolkit and enforces Redux recommendation to only store serializable data.

Serializable means it can be written down as text and converted back to original object without losing information, which doesn't work with functions. A javascript function apart from code also have scope (memory associated to it), which cannot be represented as text.

Serializability checks the whole payload (it is executed before your data reaches the store, so it doesn't know which parts will be used) and notices config. As config has methods among its members Serializability alerts you that it is not serializable. You could switch the middleware off, but it can detect genuine issues, so it's generally a better idea to just keep only relevant data in the payload.

Pavier answered 23/3, 2021 at 8:32 Comment(0)
O
1

This pattern worked for me. Instead of doing this:

export const getProducts = createAsyncThunk(
    'products/getProducts', 
    async() => {
        const res = await axios.get('http://localhost:5000/products/view-products', {withCredentials: true});
        return res;
    }
)

try this.

export const getProducts = createAsyncThunk('products/getProducts', async() => {
 return axios.get('http://localhost:5000/products/view-products', {withCredentials: true})
  .then((response) => {
    return response.data
  })
  .catch((err) => {
    console.log(err);
  });
 }
)
Overprize answered 3/8, 2023 at 18:13 Comment(0)
B
0

I solved the issue by ignoring some middleware actions from redux-persist :

import {
  persistReducer,
  FLUSH,
  REHYDRATE,
  PAUSE,
  PERSIST,
  PURGE,
  REGISTER,
} from "redux-persist";

export const store = configureStore({
  reducer: persistedReducer,
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({
      serializableCheck: {
        ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
      },
    }),
});
Berkeleianism answered 30/6, 2023 at 19:4 Comment(1)
redux-persist has absolutely nothing to do with the post.Choriamb

© 2022 - 2024 — McMap. All rights reserved.