question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Objects with an array as a prototype are not reactive

See original GitHub issue

Vue.js version

2.0.3

Reproduction Link

https://jsfiddle.net/yMv7y/1860/

Steps to reproduce

  1. Press the buttons.

What is Expected?

Both counters increment.

What is actually happening?

Very simply, Vue reactivity works for objects that are [] but not objects that have [] as a prototype. This is happening in Vue 2.0.

FancyArray.prototype = [];

function FancyArray() { }

new Vue({
  data: {
    normalArray: [],
    objectWithArrayPrototype: new FancyArray()
  },
  watch: {
    normalArray: function(a) {
      console.log("normal array triggered", a);
    },
    objectWithArrayPrototype: function(a) { // THIS WATCH IS NEVER TRIGGERED
      console.log("object with array prototype triggered", a)
    }
  },
  created: function() {
    this.normalArray.push("hey!"); // -> prints "normal array triggered, hey!"
    this.objectWithArrayPrototype.push("hello again!"); // -> prints nothing
  }
}).$mount('#app');

While this problem is easily circumvented by assigning a property in the object to be an array, it would be nice to be able to use objects that have an array as a prototype.

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Comments:11 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
yyx990803commented, Oct 31, 2016

The objects you are creating are in fact array-like objects and not real arrays. Vue only supports native Arrays or arrays that are real, proper sub-class of Array (only available in ES2015+), which can pass the Array.isArray check. This is an assumption made in multiple locations of the entire framework, adapting to it involves a lot of complexity for little gain - and is unlikely to be supported.

Also - custom array-like objects likely have far worse performance than real arrays, and I personally recommend against that pattern.

1reaction
ClickerMonkeycommented, Oct 30, 2016

I’m working on adding an extension to a library of mine and I ran into this problem as well. My first guess was to also just override Array.isArray to use instanceof but there were still errors (VueJS replaces the extended Array with a plain array - loosing your original object). I ended up doing something similar to what VueJS already does with arrays - decorate the array functions with new functions that call this.__ob__.observeArray when needed as well as this.__ob__.notify() (if this.__ob__ was defined). My collections trigger events, so this was my solution. It could similarly be applied to anyone else’s extended Array.

var $trigger = Rekord.Collection.prototype.trigger
Rekord.Collection.prototype.trigger = function (ev, args) {
  const result = $trigger.apply(this, arguments)
  const ob = this.__ob__
  if (ob) {
    switch (ev) {
      case 'add':
        ob.observeArray([args[0]])
        break
      case 'adds':
        ob.observeArray(args[0])
        break
      case 'reset':
        ob.observeArray(this.slice())
        break
    }
    ob.dep.notify()
  }
  return result
}
Read more comments on GitHub >

github_iconTop Results From Across the Web

Object prototypes - Learn web development | MDN
Prototypes are the mechanism by which JavaScript objects inherit features from one another. In this article, we explain what a prototype is, how ......
Read more >
vuejs prototype array not being watched - Stack Overflow
prototype are not reactive like a Vue instance's data properties. I agree that, in most cases, Jeff's method or using Vuex is the...
Read more >
Reactivity in Depth - Vue.js
One of Vue's most distinct features is the unobtrusive reactivity system. Models are just plain JavaScript objects. When you modify them, the view...
Read more >
Arrays, Objects and Mutations - Medium
Array.prototype.push allows us to push elements to the end of an array. This method does not return a new copy, rather mutates the...
Read more >
Disabling Prototype Extensions - Configuration - Ember Guides
Native arrays will no longer implement the functionality needed to observe them. If you disable prototype extension and attempt to use native arrays...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found