14
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Vuex】createdでstoreを呼び出してもundefinedになるんだが?

Last updated at Posted at 2023-03-22

createdでstoreを呼び出してもundefinedになるんだが?

はい、タイトル通りです。
グローバルで使いたいオブジェクトをVuexstoreに保存して、
任意のタイミングで呼び出したかったのですが、undefinedとうまく取り出せませんでした。
その原因と解決策について、備忘録として残したいと思います。

やりたいこと

Vuexstoreにオブジェクトを保管して、他のコンポーネントでも使用したい。
今回はログインしたユーザーオブジェクトをstoreに保存して、
ユーザー情報を他のコンポーネントでも自由に取り出したい。
名前とか、プロフィール画像とか。

前提条件

storeの設定

storeは以下のように、ユーザーオブジェクトをstateにセットしている。
コンポーネント側ではmapGettersを使って、stateの値を参照する。

index.js
import { createStore } from 'vuex'

const store = createStore({
  state () {
    authUser: null
  },
  getters: {
    authUser: state => state.authUser;
  },
  mutations: {
    // 認証済みユーザー情報をセット
    setAuthUser (state, AuthUser) {
      state.authUser = AuthUser;
    }
  },
  actions: {},
  }
})

export default store

保存するオブジェクト

ユーザーオブジェクトは以下のようなデータ

Object: {
  'id': 1,
  'first_name': "山田",
  'last_name': "太郎",
  'email': "test@example.jp",
  'hashed_password': "$2a$12$omQoqe9J/ex5KrK6LAHwPeLLONg2Nha5xmTRBtn4pVs.gL9nWyECC",
  'created_at': "2023-01-22T06:51:05.189Z",
  'updated_at': "2023-01-22T06:51:05.189Z",
}

うまくいかなかったパターン

色々試してみた結果、以下のことがわかった。
createdmountedの両方でstateを参照するとundefine
・テンプレート内で{{}}による呼びだしが可能だが、consoleundefineのエラーが表示
・クリックイベントではstoreのデータを参照できる。

よって、Vuex内のstateがセットされるのは
created(), mounted() のライフサイクルメソッドの後っぽい。

header_comp.js
import { mapGetters } from "vuex";

const headerComp = {
  template:
    `
      <div class="comp-header">
        <div class="lay-header">
          <div class="lay-header-right">
            <ul>
              <!-- オブジェクトが表示されている -->
              <li>{{this.user}}</li>

              <!--  クリックイベントでオブジェクト情報をconsoleに表示する -->
              <li @click="getUser">{{this.user}}</li>
            </ul>
          </div>
        </div>
      </div>
    `,
  created() {
    // undefinedになる
    console.log(this.authUser);
  },

  mounted() {
    // undefinedになる
    console.log(this.authUser);
  },

  computed: {
    ...mapGetters(["authUser"]),
  },

  methods: {
    // オブジェクトを取り出せる
    getUser(){
      console.log(this.authUser);
    },
  }
}

export default headerComp

解決策

Vuex のインスタンスメソッドである watch メソッドを使用して、
storestateデータが変更された瞬間を検知して、stateデータを取得する。

watch とは

storeデータが更新されたときにコールバック関数を呼び出すことができます。

vue.js
watch(fn: Function, callback: Function, options?: Object): Function
  • 第一引数には、storestateデータ
  • 第二引数には、第一引数の返り値を受け取り、適当な処理を
  • 第三引数には、オプションを追加することができます。

詳しい説明は公式ドキュメントを参照してください。

うまくいったコード例

created()メソッド内で、watchを用いることで、
stateデータが変更された瞬間を監視して、stateデータを取得します。

これで、state内のデータを呼び出し、名前情報を取得することができました。

header_comp.js
import { mapGetters } from "vuex";

const headerComp = {
  template:
    `
      <div class="comp-header">
        <div class="lay-header">
          <div class="lay-header-right">
            <ul>
              // 山田 太郎
              <li> {{this.user.first_name}} {{this.user.last_name}}</li>
            </ul>
          </div>
        </div>
      </div>
    `,
  data(){
    return {
      user: {},
    }
  },

// ここを変更
  created() {
    this.$watch(
    (state) => state.authUser,
      (authUser) => {
        this.user = Object.assign({}, authUser); // コピー
      }
    );
  },
  
  computed: {
    ...mapGetters(["authUser"]),
  },
  
}

export default headerComp

備考 階層を変えるとうまくいく

mapGettersでstateを読み込むファイルの階層を一つ落とすとうまく読み込むことができる。

application.jsheader_comp.jsを読み込む際には、前述したwatchを使った。
しかし、階層が一つ下のprofile/index.jsを読み込む際には、watchを使わずとも、
mapGettersstateにアクセスすることができた。

ファイル階層
mojikyo45_640-2.gif

application.js

import * as Vue from "vue";
import headerComp from "./feature/header_comp"
import router from "./../router/index"
import Vuex from './../store/index'

const App = Vue.createApp({
    template: `
        <headerComp/>
        <router-view/>
    `,
    data() {
        return {
        }
    },
    components: {
        headerComp
    },

});

App.use(router);
App.use(Vuex);
App.mount("#app");

ファイルの読み込み順などの関係で、
header_compではstateが一瞬空で表示されているのでしょうか?
詳しい原因はよく分かっていません。

最後に

ここまで見てくださりありがとうございます。
今回はstoreのデータ参照のはまりポイントについて紹介いたしました。

Vue.jsの理解はまだまだ浅いので、これからもキャッチアップを続けていきたいと思います。

14
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
14
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?