Subscribe on changes!

EventTarget instances cannot be made reactive.

avatar
Nov 17th 2022

Vue version

3.2.45

Link to minimal reproduction

https://sfc.vuejs.org/#eNp9kk1vwjAMhv+KlcvKBOmdjUnTtPOkjWMvbWYgiCZR7PKhqv99TksBbWiHSrH7vo9t2a16DUHvG1Rz9Uwm2sBAyE14KZytg48MLUQsDds9TsHS5/kNHayir+FBvA9PhSuc2ZVE8NVUb/0Dj4zum+B9j46XZVyjoDpR5o/y5UnYO6xbw8HyxjcMvEEoVJ8uFNDJcXnUQvaO+EpewKpx0oR3kE0GZk9cbizBzjoEYh+op1lxls4gQYWpUlntENhLZHyNl8mkyIjXIXr2fAoohT6qLRrWRnSM2c0oV9VEygPc8+u+79gY9lFYo0D0j/ngGQaj62BjP5nDw8WQTVKNQWtpzF4WsbjZSjaykuM5HxYqq5SAsQ47mUIiuHHMoW3vUbsuAS4mNVXDOczqMugteScH0/ZTnH/IxoSVMiknV5HiQm2YA83znFYmndmWtI/rXF46No5tjRqpnlXRHwijgAs1vWHkktxjnEU5JYwY/2P+kv7hJqwM1anuB0kZD8E=

Steps to reproduce

  1. Create a class that extends EventTarget.
class SubClass extends EventTarget {};
  1. Instantiate that class and make it reactive.
const subClass = reactive(new SubClass());
  1. Check if it is reactive using isReactive.
isReactive(subClass); // false

Further testing shows that without the class syntax sugar the line that breaks reactivity for that class is:

SubClass.prototype = Object.create(EventTarget.prototype);

What is expected?

The expected result is that the instance will become reactive.

What is actually happening?

The instance does not become reactive.

System Info

No response

Any additional comments?

Some libraries provide instances extended from EventTarget so it would be good to know why they cannot be made reactive and if there is a way around it.

avatar
Nov 18th 2022

We only make plain objects to reactive and it seems no workaround.

Object.prototype.toString.call(new SubClass()) // '[object EventTarget]' not '[object Object]'
avatar
Nov 18th 2022

Because when reactive proxies, it will judge the incoming value, and the current incoming object type is [object EventTarget] ,not within the scope of reactive proxy

avatar
Nov 18th 2022

function targetTypeMap(rawType: string) { switch (rawType) { case 'Object': case 'Array': return TargetType.COMMON case 'Map': case 'Set': case 'WeakMap': case 'WeakSet': return TargetType.COLLECTION default: return TargetType.INVALID } } The object type you pass in is ultimately judged as TargetType.INVALID ,reactive would return the instance itself

class SubClass extends EventTarget {} const obj = new SubClass() const subClass = reactive(obj); const isSubClassReactive = isReactive(subClass); console.log(obj === subClass); // true

avatar
Nov 18th 2022

Some libraries provide instances extended from EventTarget so it would be good to know why they cannot be made reactive and if there is a way around it.

The general recommendation is to not make complex class constructs reactive. We also don't want to add more complexity into the reactivity internals by supporting arbitrary native object types such as Element, Node, EventTarget etc. and then have to work around potential issues with those (i.e.: if we made Element reactive you would quickly end up with a max Call Stack exceeded error as any element could provide a circular path through the whole document tree)

Reactive state is optimally done with POJOs exclusively (plus the officially supported collection types).