Summer Sale! All accounts are 50% off this week.

ohffs's avatar
Level 50

Replacing a large array

Another in my 'bored on a Friday' series of questions. I was playing around with a little bit of code I have that has a large array of objects in the data() of the component. It loads the data from localStorage on page load and goes off to fetch the current data from an API - basically to give you something to look at as the API call takes about 10 seconds.

However, if I just do :

let newArray = await apiCall();
this.myData = newArray;

then this.myData doesn't seem to get properly replaced. The new data is there, but it's almost like it's a 'shadow'. So for instance you can click an item and it toggles a selected state - but after the api call you need to click the item twice before it 'notices' that it's clicked.

But, if I do :

let newArray = await apiCall();
this.myData = [];
this.$nextTick(() => {
      this.myData = newArray;
});

then it works perfectly. As far as I know Vue should notice that the array has been replaced so the first version should work - so I'm not sure why the second version is needed (I only tried it out of desperation).

Anyone come across this before? I'm guessing it's something to do with the way Vue tries to merge the state of the items - when they are emptied in the current 'tick' it does a full replace on the $nextTick. It seems a bit hacky though :-/

0 likes
8 replies
ouhare's avatar

Did you try to do something like:

const newArray = await apiCall()
this.myData = [ ...newArray ]

?

ohffs's avatar
Level 50

@ouhare didn't think of that - I'll give it a try :-)

@bobbybouwmann the data isn't replaced often - just once about 10s after page load. The update never properly happens - even several minutes of clicking around later - so I don't think it's just my impatience :-) I think it's something to do with the way it replaces an array :

You might think this will cause Vue to throw away the existing DOM and re-render the entire list - luckily, that is not the case. Vue implements some smart heuristics to maximize DOM element reuse, so replacing an array with another array containing overlapping objects is a very efficient operation.

Which is what makes me think setting the array to empty during 'this' tick - then replacing in the 'next' tick is forcing it to properly replace the data.

bobbybouwmann's avatar

Mmh shouldn't need to empty the array in this tick and replace it in the next tick. The next tick should just replace it all.

However I have never had any issues with updating an array with vue and next tick stuff! Do you have so much data? Or is it just something else?

ohffs's avatar
Level 50

@bobbybouwmann it's not a huge amount of data - just about 2000 objects with about 10 plain string/int/bool fields in each (it's a live view of torrents downloading). I think it's possibly related to the caching of them in localStorage. I'm doing a JSON.stringify on the array to store it and then JSON.parse to get it back - which discards vue's magic watcher/getter/setter info - so it's possibly getting confused when the replacement objects go over the top of them.

It's not a big issue - just feels a little 'hacky' to have to do it like this.

bobbybouwmann's avatar

Is there are reason why you stringify it? Why don't you just save the array of objects in localStorage as is?

Please or to participate in this conversation.