ログイン前とログイン後でヘッダーの表示を変化させたい場合。

例えば、ヘッダー右に

・ログイン前はログインボタン

・ログイン後はログインユーザー名

を表示したいとする。

 

しかし、ログイン後にヘッダーの情報だけなぜか反映されず

リロードをしないとヘッダーにユーザー情報が表示されないことがある。

 

ヘッダーにユーザー名が表示されない

↓やりたいこと(ログイン後)

 

↓実際(ログイン後)

ログインしているにも関わらず、ヘッダーがユーザー名ではなくログインボタンのまま。

 

ちなみに、ページをリロード(更新・リフレッシュ・再読み込み・F5)すると、ちゃんと表示される。

ていうかページにはユーザー情報がちゃんと表示されてるのにヘッダーだけ表示できてないってどういうことだってばよ?

 

原因と対処法

ヘッダーコンポーネントが変数の変化に気づいていない

vuexのstateの監視みたいなことをしないといけない。

 

結論だけ言うとヘッダーコンポーネントをこんな感じにする。

 

//Header.vue
<template>
    <header>
        <div>
            <b-navbar toggleable="lg" type="dark" variant="dark">
                <b-navbar-brand href="#">NavBar</b-navbar-brand>
                <b-navbar-toggle target="nav-collapse"></b-navbar-toggle>
                <b-collapse id="nav-collapse" is-nav>
                    <b-navbar-nav>
                        <b-nav-item class="active" to="/">Home</b-nav-item>
                        <b-nav-item to="/about">About</b-nav-item>
                        <b-nav-item to="/stocks/create">Post</b-nav-item>
                        <b-nav-item to="/stocks">Archive</b-nav-item>
                        <b-nav-item to="/login">Login</b-nav-item>
                        <b-nav-item to="/register">Register</b-nav-item>
                    </b-navbar-nav>

                    <b-navbar-nav class="ml-auto">
                        <b-nav-item-dropdown right v-if="isLoggedIn">
                            <template #button-content>
                                <em>{{ userName }}</em>
                            </template>
                            <b-dropdown-item href="#">Profile</b-dropdown-item>
                            <b-dropdown-item href="#">Sign Out</b-dropdown-item>
                        </b-nav-item-dropdown>
                        <button v-if="!(userName)">ログイン</button>
                    </b-navbar-nav>
                </b-collapse>
            </b-navbar>
        </div>
    </header>
</template>
<script>
    export default {
        data() {
            return {
                userName: null,
                email: "",
                isLoggedIn: false,
            };
        },
        mounted() {
            this.$store.watch(
                (state, getters) => getters.getUserName,
                (newValue, oldValue) => {
                    console.log('username changed! %s => %s', oldValue, newValue)
                    this.isLoggedIn=true
                    this.userName = newValue
                }
            )
            this.userName = localStorage.userName //これがないとリロードしたときに名前が消える
        },
        computed: {},
        methods: {},
    };
</script>

 

これだけ言われても意味わからんと思うから解説。

前提条件

  • Vuexがすでに利用できる環境
  • バックエンドの認証システムがすでに完成してる(本例ではLaravelのsanctumを利用)

 

親コンポーネントはこんな感じ。

分かってるわ!って人は飛ばして。

//App.vue
<template>
    <div>
        <Header />
        <div class="container">
            <router-view />
        </div>
        <Footer />
    </div>
</template>

<script>
    import Header from '../layout/Header'
    import Footer from '../layout/Footer'

    export default {
        components: {
            Header,
            Footer,
        },
    }
</script>

ここにヘッダーやら、ページやらのコンポーネントが格納されていくイメージ。

 

ログインフォーム

//Login.vueのメソッド部分
onSubmit() {
        axios.post('/api/login', this.form)
            .then(response => {
                const userInfo = {
                    name: response.data.user.name,
                    email: response.data.user.email,
                    token: response.data.token,
                }
                this.$store.commit("checkLogin", userInfo) //vuexに渡す
                this.$router.push('/home');
            })
}

ログインページのメソッド部分だけ書くとこんな感じ。

this.$store.commit("checkLogin", userInfo)でログインに成功したユーザーの情報(メールアドレス・パスワード・トークン)をvuexに渡している。

ログイン処理ののAPIに関しては割愛。

 

vuex

vuexはインストールされている前提で話を進めています。
//\\プロジェクトディレクトリ\resources\js\store\index.js
import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

const store = new Vuex.Store({
    state: {
        name: null,
        email: null,
        token: null,
    },
    getters: {
        getUserName(state) { return state.name } //重要
    },
    mutations: {
        message(state, message) {
            state.message = message
        },
        updateUser(state, user) {
            state.name = user.name
            state.email = user.email
        },
        checkLogin(state, userInfo) {
            //vuexのstateに格納
            state.name = userInfo.name
            state.email = userInfo.email
            state.token = userInfo.token

            //リロードされても残すようにローカルストレージに格納
            localStorage.setItem("token", state.token)
            localStorage.setItem("userName", state.name)
            localStorage.setItem("userEmail", state.email)
        },
    }
}, );
export default store;

ユーザー情報(名前・メールアドレス・トークン)をAPIを介してUserテーブルから受け取り、Vuexのstateに格納。

Vuexのstateとは、簡単に言うとどのコンポーネントファイルから見ても共通の変数を取りに行ける場所みたいなやつ。

でも更新(リロード)をすると中身が消えてしまう。

知らんけど。

 

そのため、Vuexのstateに保存した内容はローカルストレージ(リロードしても消えない共通の変数を持てる場所)にも保存する。

 

ヘッダー

お待ちかねヘッダー

//Header.vue
<template>
    <header>
        <div>
            <b-navbar toggleable="lg" type="dark" variant="dark">
                <b-navbar-brand href="#">NavBar</b-navbar-brand>
                <b-navbar-toggle target="nav-collapse"></b-navbar-toggle>
                <b-collapse id="nav-collapse" is-nav>
                    <b-navbar-nav>
                        <b-nav-item class="active" to="/">Home</b-nav-item>
                        <b-nav-item to="/about">About</b-nav-item>
                        <b-nav-item to="/stocks/create">Post</b-nav-item>
                        <b-nav-item to="/stocks">Archive</b-nav-item>
                        <b-nav-item to="/login">Login</b-nav-item>
                        <b-nav-item to="/register">Register</b-nav-item>
                    </b-navbar-nav>

                    <b-navbar-nav class="ml-auto">
                        <b-nav-item-dropdown right v-if="isLoggedIn">
                            <template #button-content>
                                <em>{{ userName }}</em>
                            </template>
                            <b-dropdown-item href="#">Profile</b-dropdown-item>
                            <b-dropdown-item href="#">Sign Out</b-dropdown-item>
                        </b-nav-item-dropdown>
                        <button v-if="!(userName)">ログイン</button>
                    </b-navbar-nav>
                </b-collapse>
            </b-navbar>
        </div>
    </header>
</template>
<script>
    export default {
        data() {
            return {
                userName: null,
                email: "",
                isLoggedIn: false,
            };
        },
        mounted() {
            this.$store.watch(//ここでvuexにおける「state.name」の値の変化を監視
                (state, getters) => getters.getUserName,
                (newValue, oldValue) => {
                    console.log('username changed! %s => %s', oldValue, newValue)
                    this.isLoggedIn=true
                    this.userName = newValue
                }
            )
            this.userName = localStorage.userName //これがないとリロードしたときに名前が消える
        },
        computed: {},
        methods: {},
    };
</script>

 

ホームコンポーネント

ログイン後に飛ぶべきページ

<template>
    <div>
        <div v-if="isLoggedIn">
            <p>{{ user.name }}</p>
            <p>{{ user.email }}</p>
        </div>
        <div v-else>
            <p>{{ $store.state.message }}</p>
        </div>
    </div>
</template>

<script>
    import Header from '../layout/Header'
    import Footer from '../layout/Footer'

    export default {
        components: {
            Header,
            Footer,
        },
        title: 'About',

        data() {
            return {
                user: {
                    name: null,
                    email: null,
                    token: null,
                },
                isLoggedIn: false,
            }
        },
        mounted() {
            this.user.name = localStorage.userName
            this.user.email = localStorage.userEmail
            this.user.token = localStorage.token
        },
    }
</script>

 

結果

これでログイン直後にリロードせずとも

この状態になった。

無制限に質問可能なプログラミングスクール!

万が一転職できない場合は、転職保障全額返金できるコースもあり!!

無制限のメンター質問対応

 

DMMウェブキャンプでプログラミングを学習しませんか?

独学より成長スピードをブーストさせましょう!

 

まずは無料相談から!

おすすめの記事