[Vuejs]-Click handler doesn't work without using a specific vuex state in the template

2👍

I’m not sure what {{currentPlayer}} specifically has to do with it, but any time you modify the component’s state and the view doesn’t update, then (assuming there is no error during rendering) it usually means either:

  1. You are mutating the state in a way which Vue cannot observe.
  2. Your state is not reactive, which can happen as a result of the previous point.

This is a red flag:

this.boardSlots[i] = [];

Vue cannot detect assignments to elements of an array like that (read Array Change Detection). You need to use splice() or push() for Vue to know about it. Or alternatively you can construct the boardSlots array in a local variable and then assign it to this.boardSlots at the end:

const boardSlots = [];

// Initialize boardSlots ...

this.boardSlots = boardSlots;

Also you’re rendering the rows and slots in a weird way; you shouldn’t be mutating any state during rendering, local or otherwise (--i). Just do this:

<div class="board-row" v-for="slots of boardSlots">
    <div class="board-slot"
        v-for="slot of slots"
        :class="[{checked: (slot.owner != 0)}, 'ownedBy-player-' + slot.owner]"
        @click="checkSlot(slot.row, slot.col)">
    </div>
</div>

But this may not have anything to do with your reactivity issue.

2👍

Adding {{ currentPlayer }} will make it a rendering dependency. When any of the rendering dependencies changes it will cause the whole template to be re-run. So in this case a change to currentPlayer will cause everything in that template to be re-rendered.

If you have some non-reactive data in your template, or you’re attempting to change data in a way that can’t be tracked by the reactivity system, then changes to that data will not trigger a re-render.

The key thing to appreciate is that when a template or render function runs it always runs the whole thing. While non-reactive changes won’t trigger a render they will still get pulled in if something else has triggered rendering. My assumption is that swapToNextPlayer makes a change to currentPlayer, triggering a re-render.

There are a number of change detection caveats to be aware of:

https://v2.vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats
https://v2.vuejs.org/v2/guide/list.html#Caveats

In this case the problem is that this line is trying to update an array by index:

this.boardSlots[i] = [];

The result is that the arrays won’t be properly entered into the reactivity system. Instead use:

this.boardSlots.push([]);

Leave a comment