Reputation: 318
I can't seem to figure out why my <v-snackbar>
component does not show when I update the Vuex state.
My setup is very simple: I have a snackbar in Snackbar.js, which is listening for changes in the state.
This Snackbar.js is imported as a child component in App.vue so that its global.
Next, I have a Test.vue which has a simple button. I expect that when I click the button, the State should be updated and the snackbar should render, but it doesn't.
By inspecting the Snackbar component in the Chrome Vue Devtools, I could see that the data actually makes it to the store, but somehow doesn't update the reactive props in Test.vue
Here are the relevant codes:
Snackbar.vue
<template>
<v-snackbar v-model="show" :top="top" multi-line rounded="pill">
{{ text }}
<v-btn text @click.native="show = false">
<v-icon>close</v-icon>
</v-btn>
</v-snackbar>
</template>
<script>
import { mapState } from 'vuex'
export default {
data () {
return {
show: false,
text: '',
top: true
}
},
computed: {
...mapState(['snackbar'])
},
created: () => {
this.unwatch = this.$store.watch(
// watch snackbar state
(state, getters) => getters.snackbar,
() => {
const text = this.$store.state.snackbar.text
if (text) {
this.show = true
this.text = text
}
}
)
},
beforeDestroy () {
this.unwatch()
}
}
</script>
App.vue
<template>
<v-app>
<v-main>
<!-- try to set a global snackbar -->
<Snackbar/>
<router-view/>
</v-main>
</v-app>
</template>
<script>
import Snackbar from '@/components/Snackbar'
export default {
name: 'App',
components: {
Snackbar
}
}
</script>
Test.vue
<template>
<v-btn @click="passData">Show snackbar</v-btn>
</template>
<script>
import { mapActions } from 'vuex'
export default {
name: 'Test',
data: () => ({
//
}),
computed: {},
methods: {
...mapActions([
'setSnackbar'
]),
passData () {
this.setSnackbar({
text: 'Simple message',
isActive: true
})
}
}
}
</script>
Store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
snackbar: {
isActive: false,
text: ''
}
},
getters: {
snackbar (state) {
return state.snackbar
}
},
mutations: {
populateSnackbar (state, payload) {
state.snackbar.isActive = payload.isActive
state.snackbar.text = payload.text
}
},
actions: {
setSnackbar (context, payload) {
context.commit('populateSnackbar', payload)
}
}
})
Upvotes: 2
Views: 1853
Reputation: 5260
The above code will show snackbar for the first time due to created hook and from next time it will not work, this is due to Vue reactivity
Here the state will get updated, but the data properties in snackbar component not received the updated data
The snackbar component can be replaced by
<template>
<v-snackbar v-model="snackbar.show" :top="top" multi-line rounded="pill">
{{ snackbar.text }}
<v-btn text @click.native="$store.dispatch('setSnackbar', {text: '', isActive: false})">
<v-icon>close</v-icon>
</v-btn>
</v-snackbar>
</template>
<script>
import { mapState } from 'vuex'
export default {
computed: {
...mapState(['snackbar'])
},
Upvotes: 3