Subscribe on changes!

Property added with Object.defineProperty() is not reactive

avatar
Jan 30th 2023

Vue version

3.2.45

Link to minimal reproduction

(Redacted, see https://github.com/vuejs/core/issues/7602#issuecomment-1779339124)

Steps to reproduce

Click "Set next (a)" on the first item. Observe that nothing happens. Click "Set next (b)" on the second item. Notice that not only its own number updates, but also the previous one.

What is expected?

I'd have expected Object.defineProperty() to behave the same as regular [[Set]] wrt reactivity.

What is actually happening?

Only regular assignment seems to create reactive properties.

System Info

No response

Any additional comments?

There is a separate proxy trap for Object.defineProperty, possibly only set() is currently used?

avatar
Oct 25th 2023

When running the example on SFC there's a warning stating you shouldn't be using v-for scoped for v-model, which is correct, in your example you v-model to a primitive number playground

So ignoring the example and circle back to the Object.defineProperty, I'm not sure if it should be reactive, what is the actual use case of it?

Not saying I don't agree with supporting this, but just wondering why Object.defineProperty is used instead of assigning directly through .[prop]

@vaakian @liuseen-l if you guys have insight on this, since you created the PRs :)

avatar
Oct 25th 2023

@pikax

When running the example on SFC there's a warning stating you shouldn't be using v-for scoped for v-model, which is correct, in your example you v-model to a primitive number playground

Wow, it appears I posted the wrong link. This looks like a demo for my students to explain that v-model on primitives in v-for doesn't work, rather than a testcase for this bug. 🤦🏽‍♀️🤦🏽‍♀️🤦🏽‍♀️ I mean, even the buttons I'm referencing in the issue aren't there 😅

Worse, I cannot seem to find the original testcase anywhere (I suspect CodePen had autosave on and I accidentally overwrote it 😭) and any attempt to recreate it has failed.

So ignoring the example and circle back to the Object.defineProperty, I'm not sure if it should be reactive, what is the actual use case of it?

Not saying I don't agree with supporting this, but just wondering why Object.defineProperty is used instead of assigning directly through .[prop]

Are you asking why Object.defineProperty() exists? 😅 Two main reasons:

  1. Creating accessors (not relevant here)
  2. Creating data properties that are not enumerable, not configurable, or both (very relevant)

There is no reason why non-enumerable/non-configurable properties should not be reactive, these are entirely orthogonal concepts.

avatar
Oct 25th 2023

Are you asking why Object.defineProperty() exists?

No, I'm asking a use case for it, where it must not be enumerable or not configurable but still being reactive.

You can still have a reactive by just returning on get the reactive

const obj2 = reactive({
  a: 1
})
Object.defineProperty(obj2, 'b', {
  enumerable: false,
  get() {
    return b.value
  },
})

// or
Object.defineProperty(obj, 'b', {
  enumerable: false,
  writable: true
})

playground