【问题标题】:Getting an error "A non-serializable value was detected in the state" when using redux toolkit - but NOT with normal redux使用 redux 工具包时出现错误“在状态中检测到不可序列化的值” - 但不是正常的 redux
【发布时间】:2020-08-25 12:35:13
【问题描述】:

我正在尝试切换我正在构建的应用程序以使用 Redux Toolkit,并注意到当我从 createStore 切换到 configureStore 时出现此错误:

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)

四处寻找后,我发现问题似乎出在我的自定义模型上。例如,品种数组是从品种模型创建的:

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

并使用它映射到一个字符串数组来创建我的 Varietal 数组,该数组进入我的状态:

// 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);

当我切换模型并将数组创建实用程序替换为返回一个普通对象数组的东西时:

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

然后,对于那个特殊的减速器,错误消失了,但是我在我的应用程序中都有这些自定义模型,在我开始将它们全部撕掉并重新编码它们只是为了能够使用我想问的 Redux 工具包如果这真的是我这样做之前的问题...

【问题讨论】:

    标签: javascript reactjs redux react-redux redux-toolkit


    【解决方案1】:

    这更有可能是来自redux-persist 的问题。 redux-toolkitgetDefaultMiddleware 中提供很少的默认中间件

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

    您可以通过提供 false 标志来禁用每个中间件。删除serializableCheck

    const customizedMiddleware = getDefaultMiddleware({
      serializableCheck: false
    })
    

    详情请查看redux-toolkitdocumentation

    [2021/10/07] 编辑

    要详细了解为什么会发生此错误,以及为什么将 serializableCheck 设置为错误会修复它,请阅读 Working with Non-Serializable Data | Usage Guide redux 工具包文档。

    此外,getDefaultMiddleware 导出已被弃用,取而代之的是使用回调表单。请参阅 Future planning: RTK 2.0? · Issue #958 · reduxjs/redux-toolkitgetDefaultMiddleware deprecated · Issue #1324 · reduxjs/redux-toolkit 了解更多原因。

    关于它被替换的内容,请参阅getDefaultMiddleware | Redux Toolkit 文档以了解更多信息:

    import { configureStore } from '@reduxjs/toolkit'
    
    import rootReducer from './reducer'
    
    const store = configureStore({
      reducer: rootReducer,
      middleware: (getDefaultMiddleware) => getDefaultMiddleware(),
    })
    

    【讨论】:

    • 谢谢你救了我!这应该是公认的答案。
    • 任何看到这个并使用 redux-persist 的人,除非你知道自己在做什么,否则不要完全禁用可序列化检查。最好专门禁用 redux-persist 中的操作。 See the answer from @AmerllicA
    • 在我的情况下,这可能是由redux-saga引起的:A non-serializable value was detected in an action, in the path: type. Value: ƒ actionCreator() { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } if (prepareAction) 上面的选项抑制了错误,但我认为这不是正确的解决方法。
    • getDefaultMiddleware 现已弃用,请参阅 boluwatife-fakorede 的回答 stackoverflow.com/a/68509710/10765649
    • 感谢@DakoJunior 的提醒,编辑了答案以包括为什么它被弃用的链接,以及如何使用新的回调语法。
    【解决方案2】:

    是的。 We've always told Redux users they should not put non-serializable values in the store。 Redux Toolkit 专门设计用于在设置 Redux 存储时帮助提供良好的默认值,作为其中的一部分,它包括检查以确保您不会意外更改数据并且不包含不可序列化的值。

    根据定义,类实例不能完全序列化,因此它正确地将这些实例标记为问题。请重写您的逻辑以将它们传递到商店。

    一般来说,React 和 Redux 应用程序应该使用纯 JS 对象和数组作为数据来编写。你不需要“模型类”。

    【讨论】:

    • 嗯。我不知道为什么你觉得有必要在我一年前写的一个答案中删除这个评论。最终它是你的代码库,你可以用它做任何你想做的事情。但作为一般规则,React 生态系统应用程序不使用模型类,而 Redux 一直非常固执己见,不允许在 Redux 存储状态中使用类。所以,这就是我们给人们的建议。
    • 添加一种方法来控制序列化从而允许存储我们想要和/或需要的每种值类型不是很好吗?
    • 如果需要,您可以customize the behavior of the serialization check middleware,包括覆盖“哪些值是可序列化的?”回调或完全关闭它。但是,我们强烈建议您不要这样做。归根结底,它是您的应用,您可以随心所欲,但这些准则的存在是有原因的。
    • 老实说,在这种情况下你可能不想使用 Redux :)
    • 这是一个糟糕的答案。它没有提供任何解决方案。 “只是不要这样做。”它甚至没有提供不这样做的理由。显得非常刻薄和粗鲁。
    【解决方案3】:

    当我想在@reduxjs/toolkit 旁边实现redux-persist 时,我在React Native 上遇到了这个问题,我收到了这个错误:

    然后我通过以下代码修复它:

    import {
      combineReducers,
      configureStore,
      getDefaultMiddleware,
    } from '@reduxjs/toolkit';
    import {
      persistStore,
      persistReducer,
      FLUSH,
      REHYDRATE,
      PAUSE,
      PERSIST,
      PURGE,
      REGISTER,
    } from 'redux-persist';
    import storage from 'utils/storage'; // in fact it is AsyncStorage
    import counter from 'reduxStore/reducers';
    
    const persistConfig = {
      key: 'root',
      storage,
    };
    
    const reducer = combineReducers({
      counter,
    });
    
    const persistedReducer = persistReducer(persistConfig, reducer);
    
    const store = configureStore({
      reducer: persistedReducer,
      middleware: getDefaultMiddleware({
        serializableCheck: {
          ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
        },
      }),
    });
    
    export const persistor = persistStore(store);
    
    export default store;
    

    实际上,这些行对我有帮助,没有它们我得到了上述错误:

    middleware: getDefaultMiddleware({
      serializableCheck: {
        ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
      },
    }),
    

    【讨论】:

    【解决方案4】:

    随着getDefaultMiddleware 的贬值,这可以通过使用来解决

       middleware: getDefaultMiddleware =>
        getDefaultMiddleware({
          serializableCheck: false,
        }),
    

    【讨论】:

    • 我们能不能只为一个reducer做这个serializableCheck false?
    猜你喜欢
    • 2021-11-11
    • 2021-06-19
    • 2021-08-03
    • 2022-11-06
    • 2021-06-20
    • 2021-01-27
    • 2023-01-16
    • 2021-11-09
    • 1970-01-01
    相关资源
    最近更新 更多