はじめに
前回、vuex-persistedstate
を利用して画面リロードでもログイン状態を保持できる様になったおかげで、ログイン状態の場合には画面を表示し、未ログイン状態の場合にはログイン画面へリダイレクト処理させることができました。
しかしここで新たな課題が発生します。
なんと別タブで画面表示した場合に、一方のタブでログアウトされたらもう一方のタブでもログイン画面へリダイレクトさせたいと言うのです。
調べてもなかなか別タブで変更されたstateやlocalStorageの値をwatchする方法が見つかりません。
さて、どうしよう…
StorageEventを使用する
Web Storage APIには、Storageオブジェクトが変更されるたびに発生するStorageEventが存在します。
このStorageEventを検知するためにイベントリスナを定義するサンプルコードがありました。
window.addEventListener('storage', function(e) {
document.querySelector('.my-key').textContent = e.key;
document.querySelector('.my-old').textContent = e.oldValue;
document.querySelector('.my-new').textContent = e.newValue;
document.querySelector('.my-url').textContent = e.url;
document.querySelector('.my-storage').textContent = JSON.stringify(e.storageArea);
});
なるほど。addEventListener
を利用するのですね。
ということで、localStorageに保存したキー「auth_info」の有無によってログイン状態を判別するhookを用意しました。
import { ref, useStore } from '@nuxtjs/composition-api'
export const useLoggedIn = () => {
const store = useStore()
const isLoggedIn = ref<boolean>(store.getters['auth/isLoggedIn'])
// ローカルストレージのログイン状態を監視
window.addEventListener('storage', (event) => {
if (event.key === 'auth_info') {
if (event.newValue) {
isLoggedIn.value = true
} else {
isLoggedIn.value = false
}
}
})
return { isLoggedIn }
}
そしてlocalStorage.removeItem('auth_info')
でキー自体を削除するコードをログアウト時の処理に組み込みました。
すると、上記のhookをページ内でwatchすることで、false
が返ってきた場合には未ログイン状態としてログイン画面へリダイレクトすることができました。
import { useLoggedIn } from '~/hooks/login/useLoggedIn'
export default defineComponent({
components: {},
layout: 'global',
middleware: ['guard/auth'],
setup() {
const router = useRouter()
const { isLoggedIn } = useLoggedIn()
watch(isLoggedIn, (val) => {
if (!val) {
// ログアウトした場合はログイン画面へ遷移
router.push('/login')
}
})
return {}
},
})
おわりに
薄々面倒だろうと気づいてはいましたが、やはり別タブの扱いは面倒でした。