Open djfrailey opened 4 years ago
When I fetch the gataData it returns a complex object. calling this.gameData = response.data
replaces the entire object. Vue only attaches watchers on object declaration. When I replace the entire object the watchers are wiped out. I use this.$set
to induce Vue to rebuild the watchers and bind them to the front end.
Could you provide me with a link to the documentation that states Vue only attaches watchers on object declaration?
My understanding is this:
Adding properties to an already declared object results in the property not being reactive.
Replacing an already declared object with a new object instance, will result in all properties on the newly referenced instance to be reactive. So this.gameData = response.data
should result in all properties from response.data
being declared reactive, since its object instance is different from the one already stored in this.gameData
https://vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats
This can somewhat be illustrated by running this jsfiddle and checking the console output.
You will see that all properties added via a new object instance have an associated get/set
method, as will the property added using this.$set
The only one that does not, is added to an already existing object without the use of this.$set
Functioning under this belief the only time a call to this.$set
should be necessary is when you need to add a property that isn't already declared on a reactive object.
Sorry, I was sitting in a hospital waiting room (waiting to pick up someone from a scheduled procedure) when I was answering this question when I got called back and probably should have opted to not hit comment and given a more fleshed out answer later.
My rushed answer led to terminology that I suspect is getting us mixed up. The situation that I was attempting to solve by using this.$set
is that the gameData object exists at the start of the game. but not all of the nodes within the squares
array exist. Additionally even though squares is numerically indexed, the squares can be filled out of order, so javascript treats squares
as an object rather than an array. The way they are populated is that the server records the move and sends back an update gameData object. Because not all of the nodes within squares
exist yet, when calling this.gameData = response.data;
the resulting gameData object has nodes within squares
that are non-reactive, just as you described above. I do not have any documentation that says "only on object declaration" those were my own words to describe the behavior I saw during development. Perhaps a better way to re-phrase the behavior I observed would be to say it thusly:
When replacing the whole gameData object without using this.$set
I observed that the sub-object squares
was non-reactive, even if the previous gameData object had a squares
sub-object that was reactive. When the complete squares
object was present at the first creation of gameData
, such as when viewing a completed game that was a draw, the squares
object was reactive, leading me to the phrasing that the reactivity was assigned on object declaration. My solution to the situation was to assign gameData
via this.$set
.
I hope that clears up my what I was trying to describe and why I assigned the data this way.
I would love to see other solutions to this type of situation if you have any insights to offer.
I noticed that you're using
this.$set
in a number of places and am curious as to why. My understanding is thatthis.$set
should only be used if you need force reactivity on an object property where Vue would otherwise fail to do so through the normal means ofthis.bar = 'foo';
wherebar
has already been declared inside of the componentsdata()
method.