saenridanra
saenridanra

Reputation: 45

Vue / Typescript computed property not updating DOM

I've read through lots of different threads regarding this topic and unfortunately was not able to find a solution.

I'm currently playing around with a vue / electron app based on typescript. Communication with the electron app is done in an async fashion. Thus, when displaying data on a view or component I often rely on async evaluation of the data I want to display. Upon reading up I came to the conclusion that I need to load data in the mounted() function and set the data on local variables when the data has been fetched.

However, problems arise when I try to utilize computed properties.

I will simplify the case and showcase what does and what doesn't work.

Imagine having the following vue code snippet:

<template>
<div>
  {{ text }}
  {{ text2 }}
</div>
</template>

<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';

@Component
export default class MyComponent extends Vue {
  @Prop() public text: string;

  private _text2: string;

  public get text2() {
    return this._text2;
  }

  public set text2(text2: string) {
    this._text2 = text2;
  }

  mounted() {
    // Works:
    this.text = "Hello world!";
    setTimeout(() => this.text = "Hello world! Overwritten.", 2000);

    // Doesn't work
    this.text2 = "Hello world!";
    setTimeout(() => this.text2 = "Hello world! Overwritten.", 2000);
  }
}
</script>

I should also add that the setter text2() gets called twice and the value _text2 is assigned. If I display _text2 instead of text2() in the template then the first assigned value is displayed. The value that is assigned in the timeout shows occasionally. I also played around with Watch() and was unsuccessful.

Maybe some of you know what I'm doing wrong here. I'd appreciate a little push into the right direction.

Upvotes: 1

Views: 1459

Answers (2)

Ben
Ben

Reputation: 407

A solution is to initialise your field that backs your property. This is a little cleaner than having to use the data field in the component decorator.

private _text2: string = '';

And then access/modify either directly or by using the getter and setter.

Upvotes: 0

saenridanra
saenridanra

Reputation: 45

So it seems that I found the solution. It seems that _text2 is not what is considered to be "reactive". Thus vue can't properly check state changes on this local variable. When I declare _text2 as part of the data function in the component declaration the value is properly recognized.

I don't think this is pretty, because data now has to be accessed using $data.

The access violation error is now gone and the value is updated just as expected.

Maybe someone has a solution that does not involve declaring variables on a separate part than the the class itself.

<template>
    <div>
      {{ text }}
      {{ text2 }}
    </div>
</template>

<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';

@Component({
  data: () => {
    return {
      _text2: ""
    }
  }
})
export default class Explorer2 extends Vue {
  @Prop() public text: string;

  public get text2() {
    return this.$data._text2;
  }

  public set text2(text2: string) {
    this.$data._text2 = text2;
  }
  
  created() {
    // Works:
    this.text = "Hello world!";
    setTimeout(() => this.text = "Hello world! Overwritten.", 2000);

    // Now it works:
    this.text2 = "Hello world!";
    setTimeout(() => this.text2 = "Hello world! Overwritten.", 2000);
  }
}
</script>

Upvotes: 1

Related Questions