Redux Toolkit日期对象序列化报错及解决方案咨询
问题:Redux状态中非序列化日期对象的处理方案
错误信息
A non-serializable value was detected in the state, in the path: `generate.createdImage.createdAt`. Value: Mon Jan 15 2024 17:10:56 GMT+0000 (Greenwich Mean Time)
相关reducer:generate/addGeneratedImage
问题背景
表单提交后在数据库创建包含createdAt日期对象的Post,返回前端后存入Redux状态,触发上述错误。
核心疑问
- 是否应在MongoDB中将日期存储为字符串?若是,如何在服务端查询此类字符串(例如获取最新5条帖子)?
- 若继续使用日期对象,应在何处进行序列化?是否在返回前端之前?
解决方案
1. MongoDB日期存储方式选择
不推荐将日期存储为字符串。MongoDB原生支持Date类型,存储日期对象有以下优势:
- 原生支持日期相关查询操作(排序、范围筛选等),性能远高于字符串类型
- 避免字符串格式不一致导致的查询错误
- 占用存储空间更小
如果非要存储为字符串,必须统一使用ISO 8601格式(如2024-01-15T17:10:56.000Z),查询最新5条时可直接按字符串排序:
// 服务端查询示例(字符串日期) const latestPosts = await db.post.findMany({ take: 5, orderBy: { createdAt: 'desc' } });
但这种方式的查询效率和可靠性都不如原生Date类型,因此优先选择存储Date对象。
2. 日期对象的序列化时机
必须在服务端返回前端之前完成序列化,将Date对象转换为可序列化的字符串(推荐ISO格式)。Redux要求状态必须是纯可序列化类型(plain object、数组、字符串、数字等),Date对象不属于此类,因此需要提前转换。
修改服务端createPostPartial函数,在返回结果时处理createdAt:
export const createPostPartial = async (imageObject: ImagePartialProps) => { const { userId, s3FileURL, imageParams, revisedPrompt } = imageObject; let post; try { post = await db.post.create({ data: { imageUrl: s3FileURL, size: imageParams.size!, hd: imageParams.quality === 'hd' ? true : false, prompt: imageParams.prompt, revisedPrompt: revisedPrompt, model: imageParams.model!, authorId: userId, }, }); } catch (error) { return { error: 'Failed to create the post', }; } // 将Date对象转为ISO格式字符串,确保可序列化 return { ...post, createdAt: post.createdAt.toISOString() }; };
前端ImagePostProps类型中createdAt已定义为string,与转换后的数据类型匹配,无需修改前端代码。后续若需要在前端使用日期对象,可通过new Date(post.createdAt)转回。
内容的提问来源于stack exchange,提问作者James Waterhouse
相关产品推荐
相关产品推荐

