You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 20:24:10