1

I want to wrap a class object in reactive, so i can trigger my methods which works on the attributes and the latest values of the attributes are displayed.

For example on this Example Code:

<script setup lang="ts">
import { reactive, nextTick } from 'vue'

class Test {
  public num: number;

  public constructor() {
    this.num = 3;
  }

  public increment = () => {
    this.num++;
  }
}

const test = reactive(new Test());
</script>

<template>
  <h1>{{ test.num }}</h1>
  <button @click="test.increment">Add 1</button>
</template>

the value of the header should show the value 4 after once pressed the button. But when pressing the button the value does not change?

Is there any cleaner solution instead of marking all class attributes as ref? I hoped I can use reactive to get this job done. A code example is at vue playground

Thanks for your help.

  • Eh, doesn’t Vue already have reactivity built in? – Kokodoko Jul 16 '23 at 15:45
  • 3
    Don't use classes without a good reason, they have numerous problems https://stackoverflow.com/a/76247596/3731501 . Here the problem is that you used an arrow without a good reason, it's bound to non-reactive this – Estus Flask Jul 16 '23 at 16:33
  • Yeah but Ehen you write a bigger data handler und an application, a extra class may can get rational from a software architect‘s perspective. – Patrick Scheich Jul 16 '23 at 19:23
  • You don't have to guess how to make a variable reactive. Vue has [example apps](https://vuejs.org/examples/) you can play around with in real-time. – Peter Krebs Jul 17 '23 at 11:04

1 Answers1

1

Vue's reactivity system works best with plain JavaScript objects, not class instances (as Estus Flask mentioned on comments correctly). But you can still use classes if you wrap each instance variable in a ref:

import { ref } from 'vue'

class Test {
  public num = ref(3);
  public increment = () => this.num.value++;
}

const test = new Test();

And in your template:

<template>
  <h1>{{ test.num.value }}</h1>
  <button @click="test.increment">Add 1</button>
</template>

Alternatively, you could use reactive with a plain JavaScript object:

import { reactive } from 'vue'

const test = reactive({
  num: 3,
  increment() { this.num++; },
});

And your template would be:

<template>
  <h1>{{ test.num }}</h1>
  <button @click="test.increment">Add 1</button>
</template>

Don't use classes. Instead, this approach is more typical in Vue and can be easier to understand and maintain.

Hope this helps!

Ali Bahrami
  • 910
  • 9
  • 21