Open LeaVerou opened 1 year ago
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).
Thanks, that's a great workaround! Hacky, yes, and fragile, but could work for now. Leaving this open in hopes for a less hacky solution down the line.
Vue version
3.3.4
Link to minimal reproduction
https://codepen.io/leaverou/pen/WNLQQJa?editors=1110
Steps to reproduce
Also note in the console that
app.foo
is wrapped by a Proxy whereasapp.bar
is not.What is expected?
bar
should behave identically tofoo
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-inEventTarget
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)