javascriptarraysvuejs3vue-props

Vue3: Computed value (array) not sorting when based on Props


I am using a computed value that returns an array. This computed value is being used in a Vue component.

<component v-for="(item, index) in sortedItems" ...more props />

The prop that I'm using to use in the computed value comes in the form of

const props = defineProps({ items: { type: Array, default: () => [] } })

The computed assignment

const sortedItems = computed(() => {
    return props.items.sort((l, r) => {
        const lValues = l.item.subItems.map(i => i.optValue)
        const rValues = r.item.subItems.map(i => i.optValue)
        const lMin = (Math.min.apply(null, lValues));
        const rMin = (Math.min.apply(null, rValues));
        return (lMin < rMin ? -1 : 1);
    })
});

Apologies for the length, but here is a representation of the data structure coming from the prop.

[
    {
        item: {
            name: "item1",
            subItems: [
                {
                    optName: "name1",
                    optValue: 60
                },
                {
                    optName: "name2",
                    optValue: 70
                },
            ]
        },
    },
    {
        item: {
            name: "item2",
            subItems: [
                {
                    optName: "name3",
                    optValue: 80
                },
                {
                    optName: "name4",
                    optValue: 90
                },
            ]
        },
    },
    {
        item: {
            name: "item3",
            subItems: [
                {
                    optName: "name5",
                    optValue: 50
                },
                {
                    optName: "name6",
                    optValue: 60
                },
            ]
        },
    },
]

I have run the sort on the dataset in a test environment outside of vue/computed/props and it works great. I am missing something when it comes to Vue. I thought maybe caching or holding previous version, but I keep coming up blank. ANy help/guidance would be greatly appreciated.


Solution

  • Vue's props for objects/arrays are references and not copies, what is happening here is that your computed is modifiying the passed prop, which is something which should definitely be avoided.

    Why does it modify the passed prop?

    Because of Array.prototype.sort(), which sorts the array in place, so both your computed value and your original one will be sorted. To not have it sort in place just copy the array, return [...props.items].sort(() => {}).

    Here is a playground version of what you want to achieve (I think).