I'm encountering an issue with the usage of v-if
alongside watchers and data in Vue. Below is a snippet from my Single File Component (SFC):
<script lang="ts">
// imports ...
export default defineComponent({
data() {
return {
store,
api: new Api(Constants.baseUrl),
game: null as (Game | null),
playerIcons: Constants.playerIcons,
gameId: this.$route.params.id as string,
poller: null as number | null,
whoseTurn: null as Color | null,
};
},
methods: {
async pollGame(): Promise<void> {
try {
this.game = await this.api.readGame(this.gameId);
// snip
} catch (error) {
alert(error);
}
},
colorToNotation(color: Color): string | null {
if (color === Color.A) {
return "A";
} else if (color === Color.B) {
return "B";
} else if (color === Color.C) {
return "C";
} else if (color === Color.D) {
return "D";
}
return null;
},
notationToColor(notation: string): Color | null {
if (notation === 'a') {
return Color.A;
} else if (notation === 'b') {
return Color.B;
} else if (notation === 'c') {
return Color.C;
} else if (notation === 'd') {
return Color.D;
}
return null;
}
},
async mounted() {
this.pollGame();
this.poller = setInterval(this.pollGame, Constants.pollingInterval);
},
unmounted() {
if (this.poller) {
clearInterval(this.poller!);
}
},
watch: {
'game.notation'(newValue) {
// snip
const playerNotation: string = newValue[newValue.length - 1];
let previousTurn: Color | null = this.whoseTurn;
this.whoseTurn = this.notationToColor(playerNotation);
console.log(`Set turn from ${this.colorToNotation(previousTurn!)} to ${this.colorToNotation(this.whoseTurn!)}`);
}
}
// snip
});
</script>
<template>
<!-- snip -->
<div v-if="game">
<div id="whose-turn" v-if="whoseTurn">
Turn:
<img class="player-icon" :src="playerIcons.get(whoseTurn)" />
{{ game.getPlayer(whoseTurn)!.name }}
</div>
<div v-else>
No turn
</div>
<!-- snip -->
</div>
<!-- snip -->
</template>
The scenario revolves around the game engine returning a notation where the last letter represents whose turn it is, for instance 'a
', 'b
', 'c
' or 'd
'. Strangely, when player 'a' takes their turn, the v-if
evaluates to false causing "No turn
" to be displayed. However, logs clearly indicate that upon fetching game data from the server, it's set to 'A
' and never becomes null again:
Console log:
Set turn from null to A
Set turn from A to B
Set turn from B to C
Set turn from C to D
Set turn from D to A
Set turn from A to B
Set turn from B to C
Set turn from C to D
Set turn from D to A
Set turn from A to B
Set turn from B to C
Set turn from C to D
Set turn from D to A
...
However, what's rendered in the browser is (listed here all at once instead of one at a time):
No turn
Turn: B
Turn: C
Turn: D
No turn
Turn: B
Turn: C
Turn: D
No turn
Turn: B
Turn: C
Turn: D
...
The logs affirm that the variable this.whoseTurn
holds the correct value, yet mysteriously the v-if
seems to retain the initial null value of this.whoseTurn
while waiting on game data from the server, hence associating turn A with null.
This situation is quite perplexing, any insights on what might be occurring?