当在 Vue 3 响应式 Map 中同时使用原始对象(raw)和其响应式代理(reactive)作为键时,会触发「Reactive Map contains both the raw and reactive versions...」警告;根本原因常是非法键值(如 NaN、undefined 或重复引用)导致 Map 内部键判等异常。
当在 vue 3 响应式 map 中同时使用原始对象(raw)和其响应式代理(reactive)作为键时,会触发「reactive map contains both the raw and reactive versions...」警告;根本原因常是非法键值(如 `nan`、`undefined` 或重复引用)导致 map 内部键判等异常。
该警告并非直接由 dialogVisible.value = true 这类常规响应式赋值引发,而是深层依赖——尤其是被用作 Map 或 WeakMap 键的对象——出现了类型或值的不一致性。正如问题定位所揭示:真正诱因是字典(即 Map 实例)中混入了 NaN 作为 key。
在 JavaScript 中,NaN !== NaN,而 Map 的键匹配依赖 Object.is() 语义。当 NaN 被意外插入 Map 作为键时,后续任何 map.get(NaN) 都会返回 undefined,且 Map 内部可能因无法正确去重而同时保留多个逻辑上“相同”的 NaN 键(实际是不同内存引用或多次包装),进而触发 Vue 对响应式对象混用的检测告警。
✅ 正确做法示例(避免非法键):
React 与 Next.js 性能优化指南,源自 Vercel 工程团队。适用于编写、审查或重构 React/Next.js 代码时使用。
// ❌ 危险:NaN 作为 Map 键 —— 触发警告且行为不可靠
const stateMap = reactive(new Map())
stateMap.set(NaN, { visible: false }) // ⚠️ 不推荐!
// ✅ 推荐:使用确定性、可比较的键(字符串/符号/响应式对象本身)
const stateMap = reactive(new Map<string visible: boolean>())
stateMap.set('contractDialog', { visible: false })
// 或使用唯一 ID(如来自 API 的 id 字符串)
if (id) {
const key = `dialog_${id}`
stateMap.set(key, { visible: true, title: t(`action.${type}`) })
}</string>
⚠️ 注意事项:
- 永远不要用 NaN、undefined、null 或 {}(空对象字面量) 作为 Map 键——它们不具备稳定可识别性;
- 若必须动态生成键,请统一转换为字符串:String(someValue) 或 JSON.stringify(someValue)(需确保输入可序列化);
- 检查所有涉及 Map.set() 的代码路径,尤其注意异步回调、表单初始化、API 返回数据解析等易出错环节;
- Vue 3 的响应式 Map(reactive(new Map()))仅对 set/delete/clear 操作做代理追踪,但键本身的合法性仍由 JavaScript 运行时保障。
? 总结:该警告本质是“响应式系统发现 Map 键存在歧义”,而非 ref 赋值错误。排查重点应放在 Map 键的生成逻辑与值稳定性 上,而非 dialogVisible.value = true 这一行代码。修复 NaN 键后,警告自然消失,且应用状态一致性得到根本保障。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










