4

When watching an array in Vue like this:

watch: {
  myarray(val) {
    // react to additions or deletions on myarray
  },
},

and adding or removing items on that array like this:

this.myarray.splice(this.myarray.findIndex((d) => d.id === myId), 1);
this.myarray.push({name: 'New Item'});

how do I watch for these additions or deletions on the array. Two ways I could do this:

  • Use v-for to generate (renderless) components and use the created()/beforeDestroy() hooks of this component.
  • Compare the old to the new version of the array and find differences (by iterating over the whole array)

But both methods would add a performance overhead to my application (There are up to a hundred thousand elements in this array).
Is there any way the watch callback can pass me a list of additions or deletions.

The (value, mutation) callback described here: https://optimizely.github.io/vuejs.org/api/instance-methods.html would be exactly what I need. Unfortunately that doesn't seem to work anymore.

6
  • Uses Vue.set(...) or vm.$set(...) for adding one element, uses Vue.delete(...) or vm.$delete(...) to delete one element. Commented Jul 24, 2020 at 17:52
  • How are you adding and deleting the elements in that array? Please read stackoverflow.com/help/minimal-reproducible-example and provide the code so your situation becomes understandable. Commented Jul 24, 2020 at 18:53
  • Hi, is there a way for you to grab the index of the element you are deleting and then you can do this data() { return { indexOfObjectDeleted: 0, } this.indexOfObjectDeleted = ......; watch: { myarray(newValOfArray, oldValueOfArray) { const valueOfObjectDeleted = oldValueOfArray[this.indexOfObjectDeleted] }, }, Commented Jul 25, 2020 at 23:23
  • Unfortunately not, the array is a prop coming from a parent component, I don't even know if anything was deleted or added on the array. Commented Jul 25, 2020 at 23:29
  • @crs, you can pass props such isArrayDeleted, indexOfArrayDeletedetc. from the parent component. Commented Jul 31, 2020 at 6:35

1 Answer 1

2

The best method I came up with so far would be overwriting the push and splice methods of the array. I don't really like this solution though, as it doesn't use Vue's built-in reactivity which does basically the same I am doing here:

created() {
  this.myarray.push = (...args) => {
    //do something with args
    return Array.prototype.push.apply(this.myarray, args);
  };
  this.myarray.splice = (...args) => {
    //do something with args
    return Array.prototype.splice.apply(this.myarray, args);
  };
  //any more array methods you want to intercept
},

Alternatively, and if you don't need existing code using push() and splice() to be compatible with this, you could of course define new functions such as push2() and splice2() to avoid overwriting the native functions.

Or you could define such functions on the component itself to act as setter for the array.

Note that when using the above snippet you loose Vues own reactivity on that array. To keep both you would have to do:

created() {
  const originalPush = this.myarray.push;
  const originalSplice = this.myarray.splice;
  this.myarray.push = (...args) => {
    //do something with args
    return originalPush.apply(this.myarray, args);
  };
  this.myarray.splice = (...args) => {
    //do something with args
    return originalSplice.apply(this.myarray, args);
  };
  //any more array methods you want to intercept
},
Sign up to request clarification or add additional context in comments.

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.