LoginSignup
1
2

More than 1 year has passed since last update.

VueでページをリロードしてもVuexの状態を保持できる様にする

Posted at

はじめに

ログイン情報を保持したり、パスワードの有効期限が切れていたら更新するまで他のページに遷移させない、などなど、
Vuexを利用し始めると、一度はページのリロードや遷移でstateの値がリセットされる現象に頭を悩ませるのではないでしょうか。

少なくとも私は半日悩みました。

リロードをしても状態を保持するためには、何らかの方法でブラウザに保存する必要があります。
自前でCookieやlocalStorageに保存する処理を実装する事もできますが、ここは先人達に習い便利なパッケージvuex-persistedstateを利用して楽をしたいと思います。
(Vuexの永続化、stateの永続化で調べると色々と出てきます)

なお、Vueのバージョンは3となります。

vuex-persistedstate

npmを使ってインストールします。

npm install --save vuex-persistedstate

Vuexの設定

今回、authモジュールとして認証関連のstoreを分ける事にしたので、メインのVuexファイルでvuex-persistedstateをプラグインとしてインポートする必要があります。
また、保持したいstateと保持したくないstateがあるので、pathsオプションで保持したいstateを明示的に指定したいと思います。
(保存先はデフォルトのlocalStorageとします)

store/index.ts
import Vue from 'vue'
import Vuex from 'vuex'
import createPersistedState from 'vuex-persistedstate'
import * as root from './root'
import * as auth from './modules/auth'

Vue.use(Vuex)

interface ModulesStates {
  auth: auth.State
}

export type RootState = root.State & ModulesStates

export default () =>
  new Vuex.Store({
    state: root.state() as any,
    getters: root.getters,
    mutations: root.mutations,
    actions: root.actions as any,
    modules: {
      [auth.name]: auth,
    },
    plugins: [createPersistedState({
      key: auth_info,
      paths: [
        'auth.isPasswordValid',
        'auth.isLoggedIn',
      ]
    })],
  })

storeの設定

ログインの状態を保持するisLoggedInというstateと、パスワードの状態を保持するisPasswordValidという二つのstateを用意しました。

store/modules/auth/state.ts
export interface State {
  isLoggedIn: boolean
  isPasswordValid: boolean
}
export const state = (): State => ({
  isLoggedIn: false,
  isPasswordValid: true,
})
store/modules/auth/mutations.ts
import { MutationTree } from 'vuex'
import { State } from '~/store/modules/auth/state'

export const mutations: MutationTree<State> = {
  setLoginState: (state: State, isLoggedIn: boolean) => {
    state.isLoggedIn = isLoggedIn
  },
  setPasswordState: (state: State, isPasswordValid: boolean) => {
    state.isPasswordValid = isPasswordValid
  },
}
store/modules/auth/getters.ts
import { GetterTree } from 'vuex'
import { RootState } from '~/store'
import { State } from '~/store/modules/auth/state'

export const getters: GetterTree<State, RootState> = {
  isLoggedIn: (state: State) => state.isLoggedIn,
  isPasswordValid: (state: State) => state.isPasswordValid,
}

storeの利用

準備が整ったので、実際にstateの値がlocalStorageに保存されているか確認します。
ログイン時に、下記の様にstateに値をセットします。

login.ts
store.commit('auth/setLoginState', true)
store.commit('auth/setPasswordState', true)

Chromeの開発ツールでlocalStorageを確認すると、下記の様に値が保存されていることが確認できます。

キー
auth_info {"auth":{"isPasswordValid":true,"isLoggedIn":true}}

middlewareの実装

認証が必要な画面で共通して利用できる様に、ログイン画面やパスワード更新画面へのリダイレクト処理をミドルウェアに切り出しました。

middleware/guard/auth.ts
import { Context } from '@nuxt/types'

export default function ({ store, redirect }: Context) {
  if (!store.getters['auth/isLoggedIn']) redirect('/login')
  if (!store.getters['auth/isPasswordValid']) redirect('/passwordUpdate')
}

おわりに

実際にはAPI等のレスポンスに応じたアクセス制御を行うのですが、
APIを実行する前段階でのフロントエンド側の制御として参考にしていただければと思います。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2