vuex-persistedstateの代替え案

前回までの経緯: https://blog.becom.co.jp/2022/03/nuxtjs.html

vuexとローカルストレージの情報を同期させるのが目的であるが、完全に同期をとるというのはハードルが高いような気がした。もしローカルストレージの値を修正した場合、ローカルストレージの値をvuexに反映させるところまでやろうとするとどうすればいいのか。そもそもvuex-persistedstateはどのようなタイミングで同期をとっていたのか。実装コードを読み解こうと思ったが時間的なものもあったので今回は下記のような案でいく。

同期する順番

  • nuxt 初動時 (onNuxtReady)
    • vuex の state 初期値が設定
    • localstorage の値の存在確認
    • vuex の mutations 機能を使う
    • localstorage の値があるとき localstorage の値を vuex の state 上書き 
    • localstorage の値がないとき vuex の state を localstorage へ書き込み
  • app 起動中の vuex 値の更新
    • 定義済みの mutations 各メソッドに localstorage 書き込みを追記

実際の実装例

mutationsをある程度整理してから実装

下記のように同じようなことをやっている箇所がたくさんあったのでそれをまとめてから、ローカルストレージに書き込みを実行する

修正前

`store/index.js`

export const mutations = {
  // ... 省略
  addIsCartShow(state, data) {
    state.isCartShow = data
  },
  addBuyStatus(state, data) {
    state.buyStatus = data
  },
  addCartAddParams(state, data) {
    state.cartAddParams = data
  },
  // ... 省略
}

修正後

`store/index.js`

export const mutations = {
  // ... 省略
  addState(state, params) {
    state[params.key] = params.data
    localStorage.setItem('vuex', JSON.stringify(state))
  },
  // ... 省略
}

vuex-persistedstateを読み込んでいる箇所を修正

修正を最低限にしたかったのでファイル名やnuxt.config.jsはそのままで流用した。

修正前

`plugins/localStorage.js`

import createPersistedState from 'vuex-persistedstate'
export default ({ store }) => {
  window.onNuxtReady(() => {
    createPersistedState({
      key: 'vuex',
    })(store)
  })
}

修正後

`plugins/localStorage.js`

`plugins/localStorage.js`
export default ({ store }) => {
  window.onNuxtReady(() => {
    syncLocalStorage(store, { key: 'vuex' })
  })
}
function syncLocalStorage(store, args) {
  const params = JSON.parse(localStorage.getItem(args.key))
  if (!params) {
    localStorage.setItem('vuex', JSON.stringify(store.state))
    return
  }
  for (const key in params) {
    if (Object.hasOwnProperty.call(params, key)) {
      const element = params[key]
      store.commit('addState', { key, data: element })
    }
  }
}

mutationsを実行している箇所を修正

修正前

  // ...
  methods: {
    async getAddress() {
      // ...
      this.$store.commit('addZipcodeParams', resZipcode)
    },
  },
  // ...

修正後

import { mapMutations } from 'vuex'
  // ...
  methods: {
    ...mapMutations(['addState']),
    async getAddress() {
      // ...
      this.addState({ key: 'zipcodeParams', data: resZipcode })
    },
  },
  // ...

まとめ

vuex-persistedstateの挙動についていろいろ考えた末、シンプルな修正にしました。nuxt.jsを使う場合とくにこだわりがなければvuexで値を管理した方が無難でしょう。しかしローカルストレージに値を保存する場合は注意した方が良いこともあります。ローカルストレージはjsのコードから簡単にアクセスできるので本当に流出してほしくない情報は保存しない方がいいです。そういうことを考えるとvuexの値を丸ごとローカルストレージに構築するというのはかなり限定的な使い方になるのかもしれません。vueをつかったspaの開発経験が浅い場合はvuexのコツを掴んでからリロードしても継続して使いたい値を一つづつローカルストレージに反映させる順番で実装した方が理解が早まると思います。