Redux Toolkit 检测到状态中的非可序列化值
问题描述
在使用 Redux Toolkit 的 configureStore 替换传统的 createStore 时,经常会遇到以下错误提示:
A non-serializable value was detected in the state, in the path: `varietals.red.0`.这个错误通常发生在 Redux 状态中包含不可序列化的值时,比如类实例、函数、Promise 或其他复杂对象。错误信息会明确指出问题所在的路径和具体值。
根本原因
Redux 的核心原则之一是状态应该是可序列化的,这意味着状态应该能够被转换为 JSON 格式。Redux Toolkit 默认包含了序列化检查中间件,它会自动检测并警告状态或操作中的非可序列化值。
常见的不可序列化值包括:
- 类实例(如自定义模型)
- 函数和 Promise 对象
- 日期对象(未转换为字符串时)
- Map、Set 等特殊数据结构
解决方案
1. 最佳实践:使用纯 JavaScript 对象(推荐)
将类实例转换为纯 JavaScript 对象是最彻底的解决方案:
// 不推荐:使用类实例
class Varietal {
constructor(id, color, varietal, isSelected, isCommon) {
this.id = id;
this.color = color;
this.varietal = varietal;
this.isSelected = isSelected;
this.isCommon = isCommon;
}
}
// 推荐:使用纯对象
export const createVarietalArray = (arr, color, isCommon) =>
arr.map(v => ({
id: uuidv5(v, NAMESPACE),
color,
varietal: v,
isSelected: false,
isCommon,
}));为什么推荐这种做法?
- 符合 Redux 设计原则
- 确保状态的完全可序列化
- 提高应用的可预测性和调试便利性
- 避免潜在的兼容性问题
2. 自定义序列化检查(临时解决方案)
如果确实需要在状态中包含某些不可序列化的值,可以配置中间件忽略特定路径:
import { configureStore } from '@reduxjs/toolkit';
const store = configureStore({
reducer: rootReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: {
ignoredActions: ['some/action/type'],
ignoredActionPaths: ['meta.arg', 'payload.timestamp'],
ignoredPaths: ['items.dates'],
},
}),
});注意事项
这种方法应该谨慎使用,仅作为临时解决方案。长期来看,仍然建议重构代码以使用可序列化的数据。
3. 完全禁用序列化检查(不推荐)
在某些特殊情况下,可以完全禁用序列化检查:
const store = configureStore({
reducer: rootReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: false,
}),
});警告
完全禁用序列化检查会失去 Redux Toolkit 提供的重要保护机制,可能导致难以调试的问题。只有在充分了解后果的情况下才应考虑此选项。
4. 使用 Redux Persist 时的特殊处理
当与 Redux Persist 一起使用时,需要忽略特定的 action 类型:
import {
persistStore,
persistReducer,
FLUSH,
REHYDRATE,
PAUSE,
PERSIST,
PURGE,
REGISTER,
} from 'redux-persist';
const store = configureStore({
reducer: persistedReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: {
ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
},
}),
});实践建议
- 优先使用纯数据结构:避免在 Redux 状态中使用类实例,转而使用简单的对象和数组
- 保持状态简洁:只存储必要的 UI 状态,复杂逻辑应该在组件或选择器中处理
- 利用 Redux Toolkit 的优势:充分利用其内置的不可变更新逻辑和开发工具
- 逐步重构:如果现有代码使用了类实例,可以逐步将其替换为纯对象
总结
Redux Toolkit 的序列化检查是一个有价值的功能,它帮助开发者遵循 Redux 的最佳实践。虽然提供了禁用或配置这些检查的方法,但最推荐的解决方案仍然是保持状态的完全可序列化。通过使用纯 JavaScript 对象而不是类实例,可以确保应用的可维护性和稳定性。