Subscribe on changes!

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

avatar
Apr 16th 2021

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.

avatar
Apr 19th 2021

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
avatar
Apr 19th 2021

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.

avatar
Apr 19th 2021

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/.

avatar
Jul 7th 2021

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.
avatar
Jul 7th 2021

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/