1

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?

2 Answers 2

4

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
  }
}
Sign up to request clarification or add additional context in comments.

Comments

1

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 :)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.