Vue3/Pinia中如何正确使用Map类型实现状态持久化
问题现象
在配置了localStorage持久化能力的Pinia Store中操作状态时,对数组执行push添加元素可以正常触发持久化、刷新后数据不丢失,但对Map类型的状态执行set添加元素时,数据无法持久化保存。
最小复现代码
component.vue
<script setup lang="ts"> import { useStore } from "./store" const store = useStore() </script> <template> <main> <button @click="store.createA" > Create new Array item </button> <ul v-if="store.array.length > 0"> <li v-for="(item) in store.array"> {{ item }} </li> </ul><br/> <button @click="store.createO" > Create Map Object </button> <ul v-if="store.mapObj.size > 0"> <li v-for="(item) in store.mapObj"> {{ item[1] }} </li> </ul> </main> </template>
store.ts
import { defineStore } from "pinia" export const useStore = defineStore({ id: "character-manager", state: () => ({ array: [] as Array<{key: string, value: string }>, mapObj: new Map() as Map<string,string> }), actions: { createA() { this.array.push({key: "key", value: "value"}) }, createO() { this.mapObj.set("key", "value") }, }, persist: { enabled: true, strategies: [{ storage: localStorage }], }, })
问题原因
核心原因有两点:
- JSON原生不支持Map类型的序列化:Pinia持久化插件默认用
JSON.stringify/JSON.parse做状态的序列化和反序列化,而JSON.stringify处理Map实例时,不会保留Map内存储的键值对,最终会序列化成空对象{},自然无法持久化存储Map内的数据。 - 默认反序列化逻辑不会还原Map实例:从localStorage读取数据时,默认逻辑只会返回普通JS对象,不会把对应字段还原为Map实例,后续调用
set等Map方法的行为也不符合预期。
数组属于JSON原生支持的数据类型,序列化、反序列化都不会丢失结构和内容,所以数组的操作可以正常持久化。
解决方案
给持久化策略自定义序列化/反序列化逻辑,手动处理Map类型的转换即可,修改后的store.ts持久化配置如下:
import { defineStore } from "pinia" export const useStore = defineStore({ id: "character-manager", state: () => ({ array: [] as Array<{key: string, value: string }>, mapObj: new Map() as Map<string,string> }), actions: { createA() { this.array.push({key: "key", value: "value"}) }, createO() { this.mapObj.set("key", "value") }, }, persist: { enabled: true, strategies: [ { storage: localStorage, // 自定义序列化器,兼容Map类型 serializer: { serialize: (state) => { return JSON.stringify(state, (_, value) => { // 遇到Map类型时,转成带标记的普通结构存储 if (value instanceof Map) { return { __customType: 'Map', entries: Array.from(value.entries()) } } return value }) }, deserialize: (storageValue) => { return JSON.parse(storageValue, (_, value) => { // 读取时遇到Map标记,转回Map实例 if (value?.__customType === 'Map') { return new Map(value.entries) } return value }) } } } ], }, })
如果状态中还用到了Set、Date等JSON不支持的原生类型,也可以按照同样的逻辑在序列化/反序列化函数中添加对应处理分支。
内容的提问来源于stack exchange,提问作者epsilonhalbe
相关产品推荐
相关产品推荐

