Should v-for remove the last element(s) when different array items are deleted?

templates

#1

Hi everyone,

I’ve been playing with Three.js and Vue.js in one project of mine for a while now.
Today I encountered a so-called “so-freaking-hard-to-think-about-and-debug-bug” and now I’m wondering if the things should work like this intentionally or we haven’t just think about it yet.

As I’m dynamically adding/removing the Three.js WebGL components, I have the remove logic for them in beforeDestory lifecycle event of a component (like material and geometry disposals, etc.).
This component is actually on of many in the list (array), which is rendered using v-for.

A bit simplified code…

<div>
     <some-component v-for="item in items" :data="item.data" :key="item.id"></some-component>
</div>
// SomeParentComponent.vue
export default {
    data: () => ({
        items: [
            { id: 1, data: { material: Object, /* ... */ } },
            { id: 2, data: { material: Object, /* ... */ } },
            { id: 3, data: { material: Object, /* ... */ } }
        ]
    })
};

// SomeComponent.vue
export default {
    props: {
        item: {
            type: Object,
            required: true
        }
    },
    beforeDestroy () {
        item.material.dispose();
        // etc.
    }
};

When altering (removing) from items array…

items.splice(1, 1);
// should result in:
// [
//   { id: 1, data: { material: Object, // etc. } },
//   { id: 3, data: { material: Object, // etc. } }
// ]

… we will actually end up with:

console.log(items); 
// [
//    { id: 1, data: { material: Object, // etc. } },
//    { id: 3, data: { material: undefined, // etc } }
// ]

I’m not sure if I understand correctly what’s going on here, but I was thinking that when I delete the second item in the array, the second some-component will call beforeDestroy. What I ended up with is I think the last item of the array calling it and the data are passed/shifted by reference to the rest of the elements. So in other words, the last item is deleted and the values are shifted. Am I correct? Is that the intentional behavior?


#2

Definitely not intentional. Usually when something like this is happening it’s related to key. Strange thing is you’re using it already. Does it still occur when your keys are something more unique? Like a random string?


#3

It surely is a random right now.

Math.random() * 1000000 / Math.random()

I think it’s worth pointing out that the items are not anonymous objects like in the example I provided, but the actual instances of a class. I guess it shouldn’t change anything, but who knows…


#4

Certainly possible. My next question was going to be if item 2 and item 3's material Object is a shared reference. Can you provide your actual code? Or better yet replicate the issue in a fiddle?


#5

I thought so, yeah, but it wasn’t shared at all. Unfortunately, the project is pretty complex at this stage, so it might take time to create a fiddle. But I’ll try my best to do this any time soon. Hope I’ll still be able to reproduce this. Thanks James.