Summary:
If you prefer, I have a video detailing my issue: https://youtu.be/Qf9Q4zIaox8
Concern with Navbar Component Not Updating on Store Change.
The issue I'm facing involves the Navbar component not updating when there is a change in the store. I have divided the component into two sections using v-if and v-else. The v-if section is displayed when the user is logged in, and the v-else section is shown when the user is not logged in.
Upon logging in, the server authenticates the user, and the client triggers a mutation to the store, setting the user and client token. This action also sets a state property called "userIsLoggedIn" to true. However, the Navbar component fails to update immediately after the user logs in, despite the isLoggedIn property being true. The update only occurs upon page refresh.
Navbar Component:
<template>
<div class="navbar">
<div class="container">
<div class="navbar-brand">
<h1 class="navbar-item">
<router-link to="/" class="has-text-black">Logo</router-link>
</h1>
</div>
<div class="navbar-menu">
<div class="navbar-end" v-if="isLoggedIn">
<div class="navbar-item">
<router-link to="/play" class="has-text-black">Play</router-link>
</div>
<div class="navbar-item">
{{user.balance.toFixed(2)}}
</div>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link">
{{user.username}}
</a>
<div class="navbar-dropdown">
<div class="navbar-item">Profile</div>
<div class="navbar-item">Deposit</div>
<div class="navbar-item" @click="logout">Logout</div>
</div>
</div>
<div class="navbar-item">
FAQ
</div>
</div>
<div class="navbar-end" v-else>
<div class="navbar-item">
<router-link to="/login" class="has-text-black">Login</router-link>
</div>
<div class="navbar-item">
<router-link to="/register" class="has-text-black">Register</router-link>
</div>
<div class="navbar-item">FAQ</div>
</div>
</div>
</div> <!— container —>
</div> <!— navbar —>
</template>
<script>
import {mapGetters} from "vuex";
export default {
name: "Navbar",
data() {
return {
user: this.$store.state.user,
}
},
computed: {
...mapGetters([
"isLoggedIn",
])
},
methods: {
logout() {
this.$store.dispatch("setToken", null);
this.$store.dispatch("setUser", null);
this.$router.push({
path: "/"
})
}
}
}
</script>
Vuex Store:
import Vue from "vue";
import Vuex from "vuex";
import createPersistedState from "vuex-persistedstate"
Vue.use(Vuex);
export default new Vuex.Store({
strict: true,
plugins: [
createPersistedState()
],
state: {
token: null,
user: null,
isUserLoggedIn: false,
},
getters: {
isLoggedIn(state) {
return state.isUserLoggedIn;
}
},
mutations: {
setToken(state, token) {
state.token = token;
if (token) {
state.isUserLoggedIn = true;
} else {
state.isUserLoggedIn = false;
}
},
setUser(state, user) {
state.user = user;
}
},
actions: {
setToken ({commit}, token) {
commit("setToken", token);
},
setUser ({commit}, user) {
commit("setUser", user);
}
}
})
Login Component:
<template>
<div class="hero is-large">
<div class="container">
<div class="hero-body">
<div class="field">
<div class="notification is-warning" v-show="error">{{error}}</div>
</div>
<h1 class="title">Login</h1>
<div class="field">
<label for="username" class="name">Username</label>
<input type="text" class="input" name="username" v-model="username">
</div>
<div class="field">
<label for="username" class="name">Password</label>
<input type="password" class="input" name="password" v-model="password">
</div>
<div class="field">
<button class="button is-link"
@click="login"
v-bind:class="{'is-loading': pending}">Login</button>
</div>
</div>
</div>
</div>
</template>
<script>
import AuthenticationService from "../Services/AuthenticationService";
export default {
name: "Login",
data () {
return {
username: "",
password: "",
error: null,
pending: false,
}
},
methods: {
async login () {
try {
// SET LOADING SPINNER
this.pending = true;
// API REQUEST
const response = await AuthenticationService.login({
username: this.username,
password: this.password,
});
console.log(response);
// CLEAR FORM
this.pending = false;
this.username = "";
this.password = "";
this.$store.dispatch("setToken", response.data.token);
this.$store.dispatch("setUser", response.data.user);
this.$router.push({
name: "Landing"
})
} catch (error) {
console.log(error);
}
}
}
}
</script>