Reputation: 1904
It is my understanding that adding a key
attribute to a component will allow the component to be reactive when that key changes, but with a v-navigation-drawer
provided by Vuetify this seems to have no impact.
I've tried even arbitrary changes to a loggedIn
key such as += 1
which would be a change sufficient enough to re-render the component.
The use case here is that I have a global navigation drawer that should show context based on if the user is/isn't logged in.
Full component
<template>
<v-navigation-drawer
absolute
right
dark
color="primary"
v-if="$store.state.globalDrawer"
v-model="$store.state.globalDrawer"
:key="loggedIn"
>
<v-container class="pa-5">
<v-layout column align-center justify-center>
<v-avatar class="ma-4" size="60">
<img v-if="!twitter" src="https://pbs.twimg.com/profile_images/1173674959731867648/6kzApb83_400x400.jpg" />
<img v-else :src="twitter.profile_image_url" />
</v-avatar>
<h2 v-if="!twitter" class="title">StreamBeacon.tv</h2>
<h2 v-else class="title">{{ twitter.display_name }}</h2>
<p v-if="!twitter" class="body-2 text-center">Enhance your Going Live experience.</p>
<p v-else class="body-2 text-center">@{{ twitter.screen_name }}</p>
<v-chip v-if="twitch.live">
<font-awesome-icon :icon="['fab', 'twitch']" />
Live Now
</v-chip>
</v-layout>
</v-container>
<!-- User is authenticated -->
<v-list dense nav>
<v-subheader>Account</v-subheader>
<v-list-item-group
color="primary"
v-if="user"
>
<v-list-item
v-for="(link, i) in accountLinks"
:key="i"
:color="activeLinkColor"
:to="link.target"
@click="changeDashboardView(link.dashboardComponent)"
>
<v-list-item-icon :color="activeLinkColor">
<v-icon v-text="link.icon"></v-icon>
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title v-text="link.text"></v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list-item-group>
<!-- User is NOT authenticated -->
<v-list-item-group
color="primary"
v-else
>
<v-list-item
@click="$eventHub.$emit('registration')"
:color="activeLinkColor"
>
<v-list-item-icon color="primary">
<v-icon>mdi-shield-account</v-icon>
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title>Sign In</v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list-item-group>
<v-subheader>Quick Links</v-subheader>
<v-list-item-group
color="primary"
>
<v-list-item
v-for="(link, i) in quickLinks"
:key="i"
:color="activeLinkColor"
>
<v-list-item-icon color="primary">
<v-icon v-text="link.icon"></v-icon>
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title v-text="link.text"></v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list-item-group>
</v-list>
</v-navigation-drawer>
</template>
<script>
export default {
data() {
return {
user: false,
twitter: false,
twitch: false,
loggedIn: false,
active: this.$store.state.globalDrawer,
activeLinkColor: "#fff",
accountLinks: [
{
"icon": "mdi-shield-account",
"dashboardComponent": null,
"text": "My Account",
},
{
"icon": "mdi-account-box-multiple",
"dashboardComponent": "connections",
"text": "My Connections"
},
{
"icon": "mdi-credit-card",
"dashboardComponent": "subscription",
"text": "Subscription",
},
{
"icon": "mdi-bug",
"dashboardComponent": "support",
"text": "Support"
},
{
"icon": "mdi-logout",
"target": "logout",
"text": "Logout"
}
],
quickLinks: [
{
"icon": "mdi-gift",
"click": "",
"text": "Gift a Streamer"
},
{
"icon": "mdi-mail",
"click": "",
"text": "Contact Us"
},
{
"icon": "mdi-library-video",
"click": "",
"text": "Our Streamers"
},
]
}
},
methods: {
checkIfAuthenticated() {
if(this.$store.state.authenticatedUser != null) {
this.user = JSON.parse(this.$store.state.authenticatedUser)
this.loggedIn = true
if(this.user.twitter) {
this.twitter = this.user.twitter
}
if(this.user.twitch_channel) {
this.twitch = this.user.twitch_channel
}
}
},
changeDashboardView(targetComponent) {
if(this.$route.name != 'dashboard') {
this.$router.replace('dashboard')
.then(() => {
this.$eventHub.$emit('changeDashboardComponent', targetComponent)
})
} else {
this.$eventHub.$emit('changeDashboardComponent', targetComponent)
}
}
},
mounted() {
this.checkIfAuthenticated()
},
watch: {
$route: function(to, from) {
this.loggedIn true
}
}
}
</script>
Are there circumstances that need to be in order for key
changes to be effective, or should this be working? I have verified that loggedIn
does properly change when logging in.
Another theory I had was that because of the v-if
directive, the component was gone during the key change, however, I debunked this theory already.
Upvotes: 1
Views: 1386
Reputation: 1904
The underlying issue, as Antonio above mentioned, is that I am not using any reactive data for the key & dependencies of the v-if
directive.
If we look using my code above, after logging in, user
is still false, which is a value dependency of the context for an authenticated user. On the mounted()
hook & a route change I look for these & update them, but that's a hacky approach.
After logging in:
The solution was to use a computed property using a Vuex getter
which will trigger a render on the component.
This being said, the changes I made to the code above are as follows (subject to change since this goes against current mistakes I need to fix, but keeping it as close to the original to make it easy to read differences).
computed: {
loggedIn: {
get() {
return this.$store.state.isLoggedIn
},
set(value) {
this.$store.commit('updateLoggedInState', value)
}
},
user: {
get() {
return JSON.parse(this.$store.state.authenticatedUser)
}
}
}
Easy solution, and a good lesson for the day! Thanks, Antonio for the guidance.
Upvotes: 1