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

我正在尝试将我正在构建的一个应用程序切换到使用 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;
}
}

然后用它映射一个字符串数组来创建我的 Varital 数组,这个数组进入我的状态:

// 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 工具包,我想在这里问一下,这是否真的是问题所在,在我这样做之前..。

151828 次浏览

是的。我们总是告诉 Redux 用户,他们不应该在存储中放置不可序列化的值.Redux Toolkit 是专门设计来帮助在设置一个 Redux 存储时提供良好的默认值的,作为其中的一部分,它包括检查,以确保您没有意外地变更您的数据,您没有包含非序列化的值。

根据定义,类实例不是完全可序列化的,所以它正确地将这些实例标记为一个问题。请重写您的逻辑 没有传递这些到商店。

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

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

enter image description here

Then I fixed it by following code:

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],
},
}),

这更有可能是 redux-persist的问题。 redux-toolkit在它的 getDefaultMiddleware中提供了很少的默认中间件

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

您可以通过提供虚假标志来禁用每个中间件

const customizedMiddleware = getDefaultMiddleware({
serializableCheck: false
})

详情请参阅 redux-toolkit 文件

[2021/10/07]编辑 :

要了解更多关于为什么会发生这个错误以及为什么将 serializableCheck设置为 false 修复它的信息,请阅读 使用非序列化数据 | 使用指南 redux toolkit docs。

此外,为了使用回调表单,getDefaultMiddleware导出被弃用。请参阅 未来规划: RTK 2.0? · 第958期 · reduxjs/redux-toolkit废弃 getDefaultMiddleware · 问题 # 1324 · reduxjs/redux-toolkit以了解更多关于原因的信息。

至于它被替换成什么,请参阅 GetDefaultMiddleware | Redux Toolkit文档了解更多信息:

import { configureStore } from '@reduxjs/toolkit'


import rootReducer from './reducer'


const store = configureStore({
reducer: rootReducer,
middleware: (getDefaultMiddleware) => getDefaultMiddleware(),
})

随着 getDefaultMiddleware的折旧,这可以通过使用

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

此示例演示了排除可序列化状态检查中间件 在这里输入链接描述

 const store = configureStore({
reducer: rootReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: false,
}),
})

我添加了带有‘ Series alizableCheck: false,’的‘ middWare’参数, problem solved. (it is not a problem actually)

来源: link

 import { configureStore } from '@reduxjs/toolkit'
import rootReducer from './reducer'
import { myCustomApiService } from './api'
    

const store = configureStore({
reducer: rootReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: false,
}),
})

我认为下面是最好的选择,如果你确切地知道什么是不可序列化的,但你需要在减少无论如何:

const store = configureStore({
reducer: { reducer },
middleware: getDefaultMiddleware => getDefaultMiddleware({
serializableCheck: {
ignoredActions: ['TYPE'],
ignoredActionPaths: ['property'],
ignoredPaths: ['reducer.property']
}
})
});

对于操作中抛出的错误,ignoredActionsignoredActionPaths就足够了。对于在状态中引发的错误,使用 ignoredPaths。检查错误消息以查看需要提供的名称。

Just like @ReFruity , my issue appeared because I was keeping the AbortController there.

编辑: 只是一个旁白,为了让 AbortController工作,我只在减速器中存储了 signalabort方法,为了让它工作,我必须这样做:

let abortMethod = abortController.abort.bind(abortController);

否则我就犯了非法调用的错误。

我也有同样的问题,我用这种方法解决了

您只需添加一个中间件并将其传递给 configureStore 即可

import { rootReducer } from "./root-reducer";
import { configureStore } from "@reduxjs/toolkit";
import logger from "redux-logger";
const middleWares = [logger];


export const store = configureStore({
reducer: rootReducer,
middleware: middleWares,
});

检查 RTK 文档,了解如何使用 ReduxPerst 设置它。

https://redux-toolkit.js.org/usage/usage-guide#use-with-redux-persist

基本上就是这句台词:

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

Which is in the configureStore call.

还有,你需要这个:

import {
persistStore,
persistReducer,
FLUSH,
REHYDRATE,
PAUSE,
PERSIST,
PURGE,
REGISTER,
} from 'redux-persist'

Redux 的核心使用原则之一是不应该将非序列化值放在状态或操作中。

然而,像大多数规则一样,也有例外。但是,如果您确实需要关闭这些警告,您可以通过将中间件配置为忽略特定的操作类型或操作和状态中的字段来自定义中间件:

configureStore({
//...
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: {
ignoredActions: ['your/action/type'],
},
}),
})

your/action/type should be replaced with actual action type which you will see in your warning message.

参考资料: https://redux-toolkit.js.org/usage/usage-guide#working-with-non-serializable-data

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

导入这些刷新清除等从恢复持久和添加中间件配置存储! 这个问题将得到解决!