Vuexにさわる
Vue3ではprovide/injectによる状態管理が推奨されているようなので使うつもりはなかったが、Global Before Guardsを使ったログイン状態によるページ制御をしようとした際にVueRouterでどう参照するのかわからなかったので使ってみる。
Vuex4になってTypeScriptへのサポートが強化されているらしい。
インストール
yarn add vuex@next --save
設定
src/store/AuthStore.ts
import { InjectionKey } from "vue"; import { createStore, useStore as baseUseStore, Store } from "vuex"; export interface IAccount { accountId: string; accountName: string; } export interface IState { account: IAccount | null; authToken: string | null; } export const key: InjectionKey<Store<IState>> = Symbol(); export const store = createStore<IState>({ state: { account: null, authToken: null, }, getters: { isLoggedIn: (state: IState): boolean => { return state.authToken ? true : false; }, getAccount: (state: IState): IAccount => { return state.account ? state.account : ({} as IAccount); }, }, actions: { login({ commit, state }: any, payload: IState) { commit("setAccount", payload); }, logout({ commit, state }: any) { commit("setAccount", { account: null, authToken: null }); }, }, mutations: { setAccount(state: IState, { account, authToken }): void { state.account = account; state.authToken = authToken; }, }, }); export function useStore() { return baseUseStore(key); }
src/main.ts
import { createApp } from "vue"; import App from "./App.vue"; import router from "./router"; import { store, key } from "./store/AuthStore"; import ElementPlus from "element-plus"; import "element-plus/lib/theme-chalk/index.css"; createApp(App).use(store, key).use(router).use(ElementPlus).mount("#app");
src/views/StoreSamplePage.vue
<template lang="pug"> MenuLayout el-row el-col(:span="10", :offset="7") p {{account.accountId}} p {{account.accountName}} p {{isLoggedIn}} el-button(type="primary", @click="login") login el-button(type="primary", @click="logout") logout </template> <script lang="ts"> import { defineComponent, computed, reactive } from "vue"; import MenuLayout from "@/layouts/MenuLayout.vue"; import { useStore, IState, IAccount } from "@/store/AuthStore"; export default defineComponent({ name: "StoreSamplePage", components: { MenuLayout, }, setup(props, context) { const store = useStore(); return { account: computed(() => store.getters.getAccount), isLoggedIn: computed(() => store.getters.isLoggedIn), login: () => store.dispatch("login", { account: { accountId: "U0000000001", accountName: "Jack", } as IAccount, authToken: "abcdefg1234567890", } as IState), logout: () => store.dispatch("logout"), }; }, }); </script>