Tech Hotoke Blog

IT観音とは私のことです。

Vue×SpringでSPA作成4【Storeのmodule分割】

f:id:TechHotoke:20211216133942p:plain

まえがき

こちらの記事の続編です。

techhotoke.hatenablog.com

目的

VueとSpringで作成したプロジェクトの構築手順の備忘録。

備忘録のため、詳細な説明を省略している部分があります。

前提

基本的なJavaの知識やSpring、Vueの知識があること。

環境

  • Java 11
  • Spring Boot2.5.6
  • Gradle 7.1.1
  • Vue2.6
  • IDESTS

Storeのmodule分割

前回はVuexのstoreフォルダ直下のindex.jsにUserのログイン情報を格納していました。

こんな感じ↓

f:id:TechHotoke:20211206231442p:plain

これだと管理するstateが増えれば増えるほどindex.jsが肥大化していくので非常によろしくないです。

こういったボトルネックは初期のうちから取り除きたいですよね。

そこでVuexのstoreはモジュールに分割して管理することができるのでそちらを実践してみようと思います。

モジュール | Vuex

まずはstoreフォルダ直下にmodulesという名称のフォルダを作成し、その中にauth.jsとindex.jsを作成します。

auth.js

import axios from 'axios'

export const auth = {
    namespaced: true,

    state: {
            emailAddress: null,
            error: false
    },
    
    getters: {
      isAuthenticated: state => {
        return state.emailAddress != null;
      },
    },
    
    mutations: {
      updateId(state, emailAddress) {
        state.emailAddress = emailAddress;
      },
      resetData(state) {
        state.emailAddress = null;
        state.error = false;
      },
      updateError(state) {
        state.error = true;
      }
    },
    
    actions: {
      login({ commit }, authData) {
        axios
          .post('/login', {
            emailAddress: authData.emailAddress,
            password: authData.password,
          })
          .then(() => {
            commit('updateId', authData.emailAddress);
          })
          .catch(() => {
            commit('updateError')
          });
      },
      logout({ commit }) {
        axios.post('/logout').then(() => {
          commit('resetData');
        });
      },
    }
}     

index.js

export { default as auth } from './auth' 

index.jsは各moduleを一括でexportするファイルとして活用します。

次にstoreフォルダ直下のindex.jsは認証情報のstateを持つ必要がなくなったので下記のようになります。

import Vue from 'vue'
import Vuex from 'vuex'
import { auth } from './modules'

Vue.use(Vuex);

export default new Vuex.Store({
  modules: {
    auth
  }
});

続いて、Login.vueの修正を行なっていきます。

<script>
import {mapState} from 'vuex'
...

mapStateヘルパー関数を使用していきたいのでこちらをscriptタグ内部でimportします。

 computed: mapState({
        isLogedIn: state => state.auth.emailAddress,
        isError: state => state.auth.error
    }),

Vuexの作法的にcomputedプロパティでstoreのstateの情報を取得します。

data関数などにstateを渡してしまうと参照渡しとなるため、値が間接的に書き換えられる恐れがあるためです。

mapStateはVuexが用意しているヘルパー関数で、this.$store.state.[module名]としていたところを上記のように記述できるようになります。

また、mapStateはオブジェクトを返却するため、複数Storeを渡した場合、ローカルの算術プロパティと共存することができなくなりますが、スプレッド演算子を使用することで、複数Storeを参照した場合の記述も可能のようです。

詳しくはこの辺りの記事をご参照ください。

Vuex: mapStateの使い方を理解する - Qiita

同時にwatch式も書き換えておきます。

 watch: {
        isLogedIn: function() {
            this.$router.push('/home')
        },
        isError: function() {
            this.hasError = true
        }
    },

次にrouter/indexを修正します。

router.beforeEach((to, from, next) => {
  // 非公開コンポーネントで未ログインの場合ログイン画面にリダイレクト
  console.log(Store)
  if (
    to.matched.some(
      record => (record.meta.isPublic || Store.state)
    )
  ) {
    next();
  } else {
    next({ path: "/", query: { redirect: to.fullPath } });
  }
});

最後にログアウト処理のパスをLogin.vueと同様のイメージで修正すれば完了です。

補足〜routerのStoreのstate取得〜

ちょっと困ったというか迷ったのですが、Storeオブジェクトの中身を確認してみると添付画像のようにmodulesにアクセスできないんですよねえ。。。知見のある方が閲覧してましたらご教示ください。。。

とりあえず今はStore.stateでアクセスできていますが、modulesが複数できたらどうなるのか・・・

一旦、この問題はStoreを複数使った時に問題として浮上してくるはずなのと、これから修正していく宿題としてここではこのように書いておきます。

コメントとしてTODOを残しておこう。。。個人開発の特権ということで。。。実務ではやらないでください。 VSCode拡張機能ToDoHighlightToDoTreeとか入れておくと見やすいですよ。

f:id:TechHotoke:20211209174134p:plain

今回はここまでとなります。

お付き合いいただきありがとうございます。