Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting an error "A non-serializable value was detected in the state" when using redux toolkit - but NOT with normal redux

I am trying to switch an app I am building over to use Redux Toolkit, and have noticed this error coming up as soon as I switched over to configureStore from createStore:

A non-serializable value was detected in the state, in the path: `varietals.red.0`. Value:, Varietal {
  "color": "red",
  "id": "2ada6486-b0b5-520e-b6ac-b91da6f1b901",
  "isCommon": true,
  "isSelected": false,
  "varietal": "bordeaux blend",
}, 
Take a look at the reducer(s) handling this action type: TOGGLE_VARIETAL.
(See https://redux.js.org/faq/organizing-state#can-i-put-functions-promises-or-other-non-serializable-items-in-my-store-state)

After poking around I found the issue seems to be with my custom models. For example the varietals array is created from a varietal model:

class Varietal {
  constructor(id, color, varietal, isSelected, isCommon) {
  this.id = id;
  this.color = color;
  this.varietal = varietal;
  this.isSelected = isSelected;
  this.isCommon = isCommon;
 }
}

and using that I map over an array of strings to create my Varietal array which goes into my state:

// my utility function for creating the array
const createVarietalArray = (arr, color, isCommon) =>
  arr.map(v => new Varietal(uuidv5(v, NAMESPACE), color, v, false, isCommon));';

// my array of strings
import redVarietals from '../constants/varietals/red';

// the final array to be exported and used in my state
export const COMMON_RED = createVarietalArray(redVarietals.common.sort(), 'red', true);

When I switched out the model and replaced the array creating utility with something that returned a plain array of objects like this:

export const createVarietalArray = (arr, color, isCommon) =>
  arr.map(v => ({
    id: uuidv5(v, NAMESPACE),
    color,
    varietal: v,
    isSelected: false,
    isCommon,
  }));

then that got the error to go away for that PARTICULAR reducer, however I have these custom models all through my app and before I start ripping them all out and recoding them simply to be able to use the Redux Toolkit I wanted to ask here if that is REALLY what the issue is before I did that...

like image 581
Hazy Avatar asked Oct 07 '22 00:10

Hazy


People also ask

What is a non serializable value?

A non-serializable value is a complex object, like a class instance or a function. It is not an array, a plain serializable object, nor a primitive (like strings, numbers, booleans, null, etc.). Otherwise, it would be included in the list of the items that JSON supports.

Should Redux state serializable?

​ It is highly recommended that you only put plain serializable objects, arrays, and primitives into your store.

What is a serializable value?

Serializable means that the data can be converted to pure text without losing information. Usually, when talking about serialization in JS, people mean that one can do the following. // data contains your data, for example: // const data = { foo: 'bar', }; const data2 = JSON. parse(JSON. stringify(data));

What is the difference between Redux and react redux?

While Redux can be used with any UI layer, it was originally designed and intended for use with React. There are UI binding layers for many other frameworks, but React Redux is maintained directly by the Redux team.

How to detect non-serializable values in Redux state?

A custom middleware that detects if any non-serializable values have been included in state or dispatched actions, modeled after redux-immutable-state-invariant. Any detected non-serializable values will be logged to the console. This middleware is added to the store by default by configureStore and getDefaultMiddleware.

What is serializability middleware in Redux?

Serializability Middleware. A custom middleware that detects if any non-serializable values have been included in state or dispatched actions, modeled after redux-immutable-state-invariant. Any detected non-serializable values will be logged to the console. This middleware is added to the store by default by configureStore and getDefaultMiddleware.

Should I disable the Serializable check in Redux-persist?

Anyone seeing this and working with redux-persist, do not entirely disable the serializable check unless you know what you're doing. It's better to specifically disable the actions from redux-persist. See the answer from @AmerllicA In my case it is probably caused by redux-saga: A non-serializable value was detected in an action, in the path: type.

What happens if a non-serializable value is detected?

Any detected non-serializable values will be logged to the console. This middleware is added to the store by default by configureStore and getDefaultMiddleware.


2 Answers

This is more likely a problem from redux-persist. redux-toolkit provide few default middleware within it's getDefaultMiddleware

import { getDefaultMiddleware } from '@reduxjs/toolkit';

You can disable each middleware by providing false flag. To remove serializableCheck

const customizedMiddleware = getDefaultMiddleware({
  serializableCheck: false
})

For details check redux-toolkit documentation.

[2021/10/07] edit:

To learn more about why this error happens, and why setting serializableCheck to false fixes it, read Working with Non-Serializable Data | Usage Guide redux toolkit docs.

Additionally, the getDefaultMiddleware export is being deprecated in favor of using a callback form. See Future planning: RTK 2.0? · Issue #958 · reduxjs/redux-toolkit and getDefaultMiddleware deprecated · Issue #1324 · reduxjs/redux-toolkit to learn more about why.

As to what it's being replaced with, see the getDefaultMiddleware | Redux Toolkit documentation to learn more:

import { configureStore } from '@reduxjs/toolkit'

import rootReducer from './reducer'

const store = configureStore({
  reducer: rootReducer,
  middleware: (getDefaultMiddleware) => getDefaultMiddleware(),
})
like image 110
Rahad Rahman Avatar answered Oct 08 '22 13:10

Rahad Rahman


Yes. We've always told Redux users they should not put non-serializable values in the store. Redux Toolkit was specifically designed to help provide good defaults when setting up a Redux store, and as part of that, it includes checks to make sure you're not accidentally mutating your data and that you're not including non-serializable values.

Class instances are by definition not fully serializable, so it's correctly flagging those instances as a problem. Please rewrite your logic to not pass those in to the store.

In general, React and Redux apps should be written using only plain JS objects and arrays as data. You don't need "model classes".

like image 65
markerikson Avatar answered Oct 08 '22 12:10

markerikson