Subscribe on changes!

JavaScript Proxy Class with Computed Method

avatar
May 1st 2022

Version

3.2.33

Reproduction link

sfc.vuejs.org/

Steps to reproduce

  • Open debugger
  • Notice 2 console logs show (expected)
  • Click Add Filter button
  • Notice the 2 lists in the HTML are updated (expected)
  • Notice only 1 console log shows (not expected, should be 2)

What is expected?

After you click the Add Filter button, there should be 2 console logs that show.

What is actually happening?

Only 1 console log shows.


I'm using a set trap in one of my classes, and I ran into a couple of issues (outlined in this SO post). The first issue was that I had to use receiver instead of target when calling the method in the set trap... calling target worked for my JS class, but when I started using it in my Vue component, it didn't work at all. The second issue is that I had to use ref with a watchEffect instead of computed as this bug shows. I'm not sure if the first issue is my own ignorance for set traps, or if it's another bug, but I can create a separate issue if need be.

avatar
May 2nd 2022

The watchEffect that uses the computed property doesn't update because the value of the computed property is a non-reactive, plain instance of new MyCollection. So any changes to do on that object are non-reactive.

So the only reactive dependency is the value of the computed itself, and that value doesn't change - it always the same MyCollection instance.

Wrapping the return value of the computed in reactive() makes your code work. However, that's not really a great pattern. computed's return values should be treated as readonly.

Some additional notes: As shown, the issue here is unrelated to the implementation details of MyCollection - the same would be happening with a plain array/object. However I still want to stress that we strongly recommend to use plain, stateless Javascript objects for reactivity, and keep complex, stateful classes and stuff out of reactivity. You already seem to have learned that this opens a can of worms.

avatar
May 2nd 2022

Hey @LinusBorg, thanks for the response. I think I understand... ref's value will wrap whatever I set in a proxy, so I essentially have a proxy of a proxy when using ref, but computed's value will just be whatever is returned (without wrapping), which is the instance of MyCollection. You're then saying if I used reactive within computed, it'd return the proxy of a proxy, which would be the same scenario as ref.

Okay, I think I was getting tripped up because they both logged as proxy in the console, but because one was a wrapper of a proxy, I didn't understand that. What an embarrassing novice mistake! Thanks for clearing that up and sorry for wasting your time.