Subscribe on changes!

[reactive] Add a way to bi-direction detect changes of original object

avatar
May 26th 2021

Version

3.0.11

Reproduction link

https://codesandbox.io/s/reverent-lewin-zs1qu?file=/src/App.vue

Steps to reproduce

There's no way to notify that the original object has been changed. So this code won't work.

<template>
  <div>{{ foo.description }}</div>
</template>

<script>
import { reactive } from "vue";

export default {
  name: "App",
  setup() {
    return { foo: reactive(new Foo()) };
  },
};

class Foo {
  constructor() {
    this.description = "placeholder description";
    setTimeout(() => {
      // this won't trigger the DOM to be updated
      this.description = "my description";
    }, 100);
  }
}
</script>

What is actually happening?

Like I showed in the example code, I can't find a workaround for this😢

avatar
May 26th 2021

We are using Proxies to detect changes, the original object stays untouched. This is by design, and there will be no way to achieve what you want.

We realize that this leads to a few caveats when using reactivity with classes, such as the one you demonstrated, but that's the way it is.

Generally, we have always recommended to use plain objects with reactivity and keep classes out of it.

avatar
May 26th 2021

@LinusBorg I could go with a workaround by doing this: https://codesandbox.io/s/stupefied-wave-ti0bb?file=/src/index.ts

but this time, the typing of reactive won't work properly in ts...

avatar
May 26th 2021

why would you make the instance reactive() if it already uses ref() internally (which are reactive)?

Just don't replace the refs, just set their value:

get url(): string {
    return this._url.value;
  }

  set url(newUrl: string) {
    this._url.value = newUrl;
  }
avatar
May 26th 2021

@LinusBorg

why would you make the instance reactive() if it already uses ref() internally (which are reactive)?

oh, because we could have any other public properties on the class instance (I have edited the example code a bit).

Just don't replace the refs, just set their value:

Because I want to init the instance property(url this case) asynchronously once if I initialized the class.

avatar
May 26th 2021

well, this works too, but you know how dirt it is..

const foo = new Foo
const fooReactive = reactive(foo)
fooReactive.initUrl()