Search code examples
reactjsreduxredux-toolkit

How to use immutable.js with RTK (redux toolkit)?


I'm migrating legacy Redux code to RTK.

With my legacy code base I was using Immutable.js (for immutability purposes), I don't need it anymore for the new code I'm gonna write, but I would like for the legacy code to keep working without touching it, and while using configureStore from RTK. But my apps throws :

Invariant failed: A state mutation was detected between dispatches, in the path 'app._values._tail.array.0._values._root.array.0.array.16._defaultValues.gcm.__hash'. This may cause incorrect behavior. (https://redux.js.org/style-guide/style-guide#do-not-mutate-state)

I get it, it's because I change the object instance, I can disable the error doing so :

immutableCheck: false,
serializableCheck: false,

but IMO it disables too much, I would like to keep these settings on, but for Immutable.js to bypass the immutability check. I found this piece of outdated code that looks like what I'm trying to achieve

// Augment middleware to consider Immutable.JS iterables serializable
const isSerializable = (value) =>
  Iterable.isIterable(value) || isPlain(value)
const getEntries = (value) =>
  Iterable.isIterable(value) ? value.entries() : Object.entries(value)
const serializableMiddleware = createSerializableStateInvariantMiddleware({
  isSerializable: () => true // all values will be accepted
  isSerializable,
  getEntries,
})
const store = configureStore({
  reducer,
  middleware: [serializableMiddleware]
})

here https://github.com/reduxjs/redux-toolkit/pull/141/files but it's not working, Iterable is now Collection and has no isIterable function, I've tried isImmutable but it's not working either.

Now the file looks like this : https://github.com/reduxjs/redux-toolkit/blob/master/docs/api/otherExports.mdx, there's no trace of Immutable.js.

What can I do ?

cross-post: https://github.com/reduxjs/redux-toolkit/discussions/3539


Solution

  • @EskiMojo14, one of the maintainers on RTK was able to find a solution for me :

    the serializableCheck and immutableCheck are two separate checks, and we want you to customise them using getDefaultMiddleware.

    For example, something like the below (untested) code might work:

    import { configureStore, isImmutableDefault, isPlain } from "@reduxjs/toolkit";
    import { isImmutable } from "immutable";
    
    const store = configureStore({
      reducer,
      middleware: (getDefaultMiddleware) =>
        getDefaultMiddleware({
          immutableCheck: {
            isImmutable: (value) => isImmutable(value) || isImmutableDefault(value),
          },
          serializableCheck: {
            isSerializable: (value) => isImmutable(value) || isPlain(value),
            getEntries: (value) =>
              isImmutable(value) ? value.entries() : Object.entries(value),
          },
        }),
    });