I created an info-bar, an area I want to update with info from the component. I added it as a child of App.vue
:
<template>
<div id="app">
<InfoBar /> // my info-bar
<router-view/>
</div>
</template>
To be able to update m<InfoBar />
from other components, I decided to try using Vuex
and use mutations
to change info:
Vuex Store:
export const store = new Vuex.Store({
state:{
infoBarText: "Text from Vuex store" , // initial text for debugging
},
mutations:{
setInfoBarText(state,text){
state.infoBarText = text;
}
}
infobar.vue
<template>
<div>
{{infoString}} // the result is always "Text from Vuex store"
</div>
</template>
<script>
export default {
name: "infoBar",
data() {
return {
infoString: this.$store.state.infoBarText
}
}
Now, I would like to update the text using the Vuex mutation from other component:
other.vue:
mounted() {
this.$store.commit("setInfoBarText", "Text from Component");
}
I checked the state
of infoBarText
with Vue developer tools and it successfully changed to "Text from Component"
but it's not changed the text in the component.
What I am doing wrong?
Vuex stores are reactive. When Vue components retrieve state from it, they will reactively and efficiently update if the store's state changes. You cannot directly mutate the store's state. The only way to change a store's state is by explicitly committing mutations.
To persist Vuex state on page refresh, we can use the vuex-persistedstate package. import { Store } from "vuex"; import createPersistedState from "vuex-persistedstate"; import * as Cookies from "js-cookie"; const store = new Store({ // ...
Key-changing to force a component refresh We add a key attribute to our component, and then change that key whenever we need the component to be re-rendered. Every time that forceRerender is called, the value of componentKey will change.
In Vuex, mutations are synchronous transactions: store. commit('increment') // any state change that the "increment" mutation may cause // should be done at this moment.
You should be using computed
instead of data
, because data
itself is not reactive once it is assigned. This will fix your issue:
export default {
name: "infoBar",
computed: {
infoString: function() {
return this.$store.state.infoBarText;
}
}
}
Proof-of-concept:
const infobar = Vue.component('infobar', {
template: '#infobar-template',
computed: {
infoString: function() {
return store.state.infoBarText;
}
}
});
const store = new Vuex.Store({
state: {
infoBarText: "Text from Vuex store", // initial text for debugging
},
mutations: {
setInfoBarText(state, text) {
state.infoBarText = text;
}
}
});
new Vue({
el: '#app',
methods: {
updateText() {
store.commit("setInfoBarText", "Text from Component");
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.22/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/3.0.1/vuex.min.js"></script>
<div id="app">
<InfoBar></InfoBar>
<button @click="updateText">Update text</button>
</div>
<script type="text/x-template" id="infobar-template">
<div>
{{infoString}}
</div>
</script>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With