Reputation: 4090
I have a Vue app where I'm trying to make a thin wrapper over the Mapbox API. I have a component which has some simple geojson data, and when that data is updated I want to call a render function on the map to update the map with that new data. A Vue watcher should be able to accomplish this. However, my watcher isn't called when the data changes and I suspect that this is one of the cases that vue reactivity can't catch. I'm aware that I can easily fix this problem using this.$set
, but I'm curious as to why this isn't a reactive update, even though according to my understanding of the rules it should be. Here's the relevant data model:
data() {
return{
activeDestinationData: {
type: "FeatureCollection",
features: []
}
}
}
Then I have a watcher:
watch: {
activeDestinationData(newValue) {
console.log("Active destination updated");
if (this.map && this.map.getSource("activeDestinations")) {
this.map.getSource("activeDestinations").setData(newValue);
}
},
}
Finally, down in my app logic, I update the features on the activeDestination by completely reassigning the array to a new array with one item:
// Feature is a previously declared single feature
this.activeDestinationData.features = [feature];
For some reason the watcher is never called. I read about some of the reactivity "gotchas" here but neither of the two cases apply here:
Vue cannot detect the following changes to an array:
When you directly set an item with the index, e.g. vm.items[indexOfItem] = newValue
When you modify the length of the array, e.g. vm.items.length = newLength
What am I missing here that's causing the reactivity to not occur? And is my only option for intended behavior this.set()
or is there a more elegant solution?
Upvotes: 1
Views: 2441
Reputation: 619
If you need to watch a deep structure, you must write some params
watch: {
activeDestinationData: {
deep: true,
handler() { /* code... */ }
}
You can read more there -> https://v2.vuejs.org/v2/api/#watch I hope I helped you :)
Upvotes: 1
Reputation: 10382
as default vue will do a shallow compare, and since you are mutating the array rather than replacing, its reference value is the same. you need to pass a new array reference when updating its content, or pass the option deep: true
to look into nested values changes as:
watch: {
activeDestinationData: {
handler(newValue) {
console.log("Active destination updated");
if (this.map && this.map.getSource("activeDestinations")) {
this.map.getSource("activeDestinations").setData(newValue);
}
},
deep: true
}
}
Upvotes: 4