'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.
Solution 1:[1]
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>
Solution 2:[2]
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.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Ben |
