'Vuejs/Nuxtjs watch is unable to watch for changes within the Array of Objects from Vuex Store
I am developing an application using Vuejs/Nuxtjs within this application I have a component IdentifiersNode.vue within that I would like to watch for a Vuex Store array identifiersArray.
I am able to watch the identifiersArray for direct changes such as push, direct key-value changes but when I add a new object to the object within the identifiersArray then watch would not work for some reason.
Following is the watch function in my IdentifiersNode.vue:
watch: {
'$store.state.modules.identifiersInfoStore.identifiersArray': {
handler (val) {
console.log('WATCH : ' + JSON.stringify(val, null, 4))
},
deep: true
}
},
Following are the changes happening to my identifiersArray within the Vuex Store Mutations present in identifiersInfoStore .js:
saveIdentifiersInfo (state, payload) {
// Upon saving the Identifiers info save the information into respective object of identifiersArray
const identifiersNode = state.identifiersArray.find(node => node.identifiersId === state.currentNodeId)
console.log('NODE BEFORE : ' + JSON.stringify(identifiersNode, null, 4))
identifiersNode.instanceData = payload.instanceData
console.log('NODE ARRAY AFTER : ' + JSON.stringify(state.identifiersArray, null, 4))
},
As we can see I am adding an object to an existing object within the identifiersArray but when I do this I would expect my watch function to trigger in IdentifiersNode.vue as I have deep: true but for some reason, it does not work at all.
Can someone please tell me if it's possible to detect even a minute change to an array using the Vuex store and Vue watch? If not then what is an alternative that I can take?
Following is my identifiersNode from console.log:
NODE BEFORE : {
"identifiersId": 1,
"name": "identifiersNode1"
}
Following is the state.identifiersArray from console.log:
NODE ARRAY AFTER : [
{
"identifiersId": 1,
"name": "identifiersNode1",
"instanceData": {
"name": "Batman",
"job":"IT"
}
}
]
Solution 1:[1]
Providing the answer can be helpful to someone else in the future.
I was actually appending the object to an existing object in Array within Vuex Store. Hence, the watch was not able to identify the change. I changed it to vue.set which worked for me.
Previously I was using to append to my existing object:
identifiersNode.instanceData = payload.instanceData
Later I changed to:
// Use the Vue reactive approach to add the instanceData object to existing object
Vue.set(identifiersNode, 'instanceData', payload.instanceData)
Following is my watch in Vue component, I used this code within my mounted can also be used within watch as well:
// Watch for the changes on the identifiers array
this.$watch('$store.state.modules.identifiersInfoStore.identifiersArray', (val) => {
console.log(JSON.stringify(val,null,4))
}, { immediate: true, deep: true })
Solution 2:[2]
If you are using vuex, I would recommand using mapGetters to get your items from the store. This will automatically watch the values and re-render each time your items changes.
Here is the documentation : documentation
Little example
Store
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
const state = {
data: ["Hello", "world"]
};
const mutations = {
addItem(state, item) {
state.data.push(item);
}
};
const getters = {
getData: (state) => state.data
};
export default new Vuex.Store({
state,
mutations,
actions,
getters
})
Component
<template>
<div>
<h2>{{ data }}</h2>
<input type="text" v-model="inputValue" />
<button @click="addItemToStore">add item</button>
</div>
</template>
<script>
import { mapGetters, mapMutations } from "vuex";
export default {
name: "HelloWorld",
computed: {
...mapGetters({
data: "getData",
}),
},
data: () => {
return {
inputValue: "",
};
},
methods: {
addItemToStore() {
this.addItem(this.inputValue);
this.inputValue = "";
},
...mapMutations({
addItem: "addItem",
}),
},
};
</script>
Here is a codepen as an example : https://codesandbox.io/s/vuex-store-forked-bl9rk0?file=/src/components/HelloWorld.vue
If you want to change an object property (Or in your case addind a new object to an array which is a property of your object) the best thing to do is completely re-push the current object.
for example if you have an array like [{id: 1, values: [1,2,3]}, {id: 2, values: [4,5,6]}] you can update values with the js splice method :
addValue(state, {id, valueToAdd}){
const pos = state.arr.findIndex(x => x.id === id)
if (pos !== -1){
const newObj = {...state.arr[pos]}
newObj.values.push(value)
state.arr.splice(pos, 1, newObj)
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | BATMAN_2008 |
| Solution 2 |
