vuex-persistedstateにES6のMapオブジェクトを混ぜる

2019-10-17

概要

vuexのstoreにMapオブジェクトを入れていたが、それをvuex-persistedstateを使ってlocalStorageに保存したかった。 Mapオブジェクトはkeyとvalueの順番を保証した状態でkeyのみでvalueを持ってこれたりするので便利だと思うが cookieやlocalStrageに保存する際の常套手段であるJSON.parseが使えないため Array.from(Mapオブジェクト)で一旦オブジェクトに変換してからJSON.parseして保存する必要がある。

vuex-persistedstate(https://github.com/robinvdvleuten/vuex-persistedstate) はvuexのstoreの値をlocalStorage等に保存して永続化するのに人気のプラグイン。

実装

今回はnuxtjsで利用。 example.myObjectのstateだけをマップオブジェクトにしてlocalStorageに保存することがゴール。

nuxtjsでプラグインとして読み込むファイル

import createPersistedState from 'vuex-persistedstate'export default ({ store, isHMR }) => { if (isHMR) return if (process.client) { window.onNuxtReady((nuxt) => { createPersistedState({ paths: ['example.myObject'], setState(key, state, storage) { state.example.myObject = Array.from(state.example.myObject) return storage.setItem(key, JSON.stringify(state)) }, subscriber(store) { store.commit('example/myObjectToMapObject') return function(handler) { return store.subscribe(handler) } } })(store) }) } }

store/example.js

export const state = () => ({ myObject: new Map() }) export const mutations = { myObjectToMapObject(state) { state.myObject= new Map(state.myObject) } } export const actions = { 略 }

これで求めていた動作にはなった。

ハマった点

vuex-persistedstateのオプションで getStateというのがあったのでcreatePersistedStateでそれつかって

getState(key, storage, value) { try { const value = storage.getItem(key) if (value) { const state = JSON.parse(value) state.example.myObject = new Map(state.example.myObject) return state } else { return undefined } } catch (err) {} return undefined },

としてMapに戻すと vuex-persistedstate内でdeepmerge(https://www.npmjs.com/package/deepmerge) のmarge時にmap型が空のオブジェクトに変換されてしまう点。

仕方なくmap変換用のmutation作ってcommitすることにした。