Properties of objects that inherit from EventTarget are not reactive
Vue version
3.3.4
Link to minimal reproduction
https://codepen.io/leaverou/pen/WNLQQJa?editors=1110
Steps to reproduce
- Visit testcase
- Press "Increase foo.x". Notice how the value updates.
- Press "Increase bar.x". The value does not update
Also note in the console that app.foo
is wrapped by a Proxy whereas app.bar
is not.
What is expected?
bar
should behave identically to foo
What is actually happening?
bar.x
is not reactive.
System Info
No response
Any additional comments?
I wonder if this is intentional behavior to avoid wrapping DOM nodes and other built-ins. In that case, checking for its children explicitly might be a better choice, since extending EventTarget
is the Web Platform's currently recommended way for authors to create data objects that can emit and listen to events. Or, perhaps there is a clever test to distinguish built-in EventTarget
descendants from author objects.
Anyhow, it would be unfortunate if supporting events in one's objects breaks Vue — especially since this seems like a small improvement I can easily see people doing thinking it cannot break anything (e.g. see articles like this)
Vue only allow ordinary objects and a few built-ins (Array
, Map
, etc.) to be made reactive (source).
The crux is how Vue currently checks if an object x
is ordinary: it checks if x.toString()
equals "[object Object]"
(source).
While foo.toString()
returns "[object Object]"
, bar.toString()
returns "[object EventTarget]"
. I've checked that overriding the Symbol.toString
getter in the class to return "Object"
, although hacky-ish, indeed fix the reactivity problem (at least on the provided demo).