In a template, a v-for item variable based on a computed property does not equal the data property it just has been assigned to with an event
Version
3.0.11
Reproduction link
https://jsfiddle.net/s596Lw1x/7/
Steps to reproduce
- Click on one of the numbered buttons
What is expected?
The button clicked last should be red
What is actually happening?
Buttons remain grey after a click
Works as expected when the items
array is defined in data (https://jsfiddle.net/xg1m9rtq/5/) or when wrapped in reactive
in the computed prop (https://jsfiddle.net/ur8t6who/).
I suspect the activeItem === item
check does not work because activeItem
is wrapped in a reactive proxy and item
is not.
In Vue3, this should be the expected behavior, and it has nothing to do with the computed. Let's say you have a raw array and a ref:
const rawArr = [{ a: 1 }, { b: 2 }]
const item = ref(null)
item.value = rawArr[0]
console.log(item.value === rawArr[0]) // false, should be expected
I understand the underlying problem and the principle of ref/reactive, but options api users do not call the reactivity api explictly. The template works if the array comes out of data
, but does not work if the array comes out of a computed prop.
This also used to work in vue2 and for it to stop working in the options api and only for computed props seems confusing.
My initial point is that it should be the user’s responsibility, but I realized that this might be a breaking change, it works in vue2 https://jsfiddle.net/HcySunYang/5hqt3su6/2/.
This is technically wrong usage anyway - you should not store values created inside a computed getter into your actual state tree.
The reason is that objects created inside a computed getter are temporary/transient/ephemeral - every time the computed updates, new objects will be created, so they should never be used for reference/equality checks.
The example works in Vue 2 only because your computed property has no dependencies so it never changes - so why is it a computed property in the first place?
As you can see, it breaks as soon as you add a dependency to the computed property: https://jsfiddle.net/6d0o9pvt/
When you click x++
in the above example, the list becomes a whole new array so your active item is lost.
Summary:
- The usage is incorrect if computed has dependencies.
- If it doesn't have dependencies, it should not be a computed property.
I get your point about computed properties being transient and storing references to it this way is problematic.
I our real world case the computed property actually has dependencies, which get transformed. Looks like I went too minimal in my reproduction. The event used is also much more short lived (mouseenter/mouseleave), so we never noticed any problem when the computed property got updated, but the active item referenced an outdated item in Vue 2.
Here's an example where a dependency gets transformed and used with mouseenter/mouseleave: https://jsfiddle.net/5jdbf62k/2/