In my Vue 2 application I have a big object that is passed from the root component down several levels to some child components as a prop. When I change some property of the object the child components should update and rerender. In some cases they do, in other cases they don't. I need some help spotting why it does not work.
Here is a child component, which does not update:
<template>
<div class="upgradeBar">
{{level}}
<div
v-for="lvlNum in maxLevel + 1"
class="level"
v-bind:class="{reached: isLevelReached(lvlNum - 1)}"
></div>
<button
class="btnUpgrade"
@click="onLevelUp()"
v-if="!isLevelReached(maxLevel)"
>
+
</button>
</div>
</template>
<script lang="ts">
import {Component, Prop, Vue} from 'vue-property-decorator';
import Upgradable from "../../../models/Upgradable";
@Component()
export default class UpgradeBar extends Vue {
name: 'UpgradeBar';
@Prop() entity: Upgradable;
get level(): number {
return this.entity.level;
}
get maxLevel(): number {
return this.entity.MAX_LEVEL;
}
onLevelUp() {
this.entity.levelUp();
}
isLevelReached(level: number): Boolean {
return this.entity.level >= level;
}
}
</script>
The component is called like this:
<UpgradeBar :entity="entity" />
All the code works. When I click the btnUpgrade
button entity.level is indeed changed, but I need to close and reopen the component to see the changes. Also the browser dev tool does not show the change instantly. I need to click on the component to refresh the values in the debugger.
EDIT:
The entity
class looks basicly like this (excerpt):
class Entity {
name: string = 'some name';
level: number = 1;
}
I searched deeper and it seems to boils down to this: Some properties of the object are reactive (they have getters / setters created by vue) and some don't. entity.name
has a setter, so changing it updates the component. entity.level
does not. Here's the question: Why are they treated differently? Here is a log:
Can't tell for sure without seeing the code for entity.levelUp
, but it seems like a reactivity issue, that may be solved by using Vue.$set
inside that function.
You can confirm this being the case by adding this.$forceUpdate();
after this.entity.levelUp();
update
this._level = this._level + 1;
can be changed to
Vue.$set(this, _level, this._level + 1);
You will need to import Vue in that component/file to access the $set function
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With