2

when I update a value in an array of the store, the interface doesn't reflect the change.

Goal: I'm trying to display a simple minesweeper grid. Once I click on a cell, the object attach to that cell should update isRevealed to true to say is was revealed and Vuejs should add the class dug to that cell.

What's working: isRevealed is switched to true.

What was working: using only props everything was working, but trying to learn VueJS and including Vuex store the UI doesn't update anymore with the array.

Structure:

App shows a grid and grid shows multiple cell.

store.js for Vuex

import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export const store = new Vuex.Store({
    state: {
        GameGrid: [],
    },
mutations: {
    revealCell(state, cell) {
        state.GameGrid[cell.y][cell.x].isRevealed = true;
        console.log("revealCell ", cell);


    },
});

GameGrid contain the following: 10 arrays of 10 objects:

{
    isRevealed: false,
    x: 0,
    y: 0
    ...
}

grid.vue, nothing special, display every cell

<template>

    <div class="grid">
        <div v-for="row in $store.state.GameGrid" class="row">
            <app-cell v-for="col in row" :cell="col"></app-cell>
        </div>
    </div>

</template>

cell.vue:

<template>
    <div
        @click="dig"
        :class="{dug: cell.isRevealed, dd: cell.debug}">
        <span class="text" v-html="cell.display"></span>
        <span class="small">{‌{ cell.code }}</span>
    </div>
</template>
<script>
    export default {
        props: {
            cell: {
                type: Object
            },
        },
        data: function() {
           return {
               display: null,
           }
        },
        methods: {
            dig() {
                this.$store.commit('revealCell', this.cell);
            },
    }
</script>

Edit accoridng to pirs answer:

Grid.vue file

<template>

    <div class="grid">
        <div v-for="row in gameGridAlias" class="row">
            <app-cell v-for="col in row" :cell="col"></app-cell>
        </div>
    </div>

</template>

<script>
    import { mapState } from 'vuex';
    import Cell from './Cell.vue';
    export default {
        components: {
            'app-cell': Cell,
        },
        data: {
                gameGridAlias: []
        },
        methods: {

        },
        computed: mapState({
            gameGridAlias: state => state.GameGrid
        })

    }

</script>

Note that I get The "data" option should be a function that returns a per-instance value in component definitions. error since data doesn't return a function.

My functions to set isRevealed are on the cell.vue though. I'm still seeing no UI updates (except when I'm saving?). Cells with this.cell.isRevealed = true confirmed with console.log but no change in classes.

Here is how I'm populating GameGrid

This function is calling when the user press a button on the hmm, home page? App.vue file.

     generateGrid() {
          console.log("generateGrid");
          //Generate empty play grid
          for(let y = 0; y < this.$store.state.GameGridHeight; y++) {
              this.$store.state.GameGrid[y] = new Array();
              for(let x = 0; x < this.$store.state.GameGridWidth; x++) {
                  this.$store.state.GameGrid[y][x] = {
                      content: 'Empty',
                      code: 0,
                      isRevealed: false,
                      x: x,
                      y: y,
                      debug: false,
                  };
              }
          }
      }, //End generateGrid
3
  • 1
    How are you populating gamegrid Commented Nov 10, 2017 at 1:34
  • I've updated the question to include this part, thanks!! :) Edit: should I push something instead? Commented Nov 10, 2017 at 2:56
  • Yep there's the problem. vuejs.org/v2/guide/list.html#Caveats. Commented Nov 10, 2017 at 3:27

2 Answers 2

2

In your grid.vue, you should use computed and mapState to update the props

It would be like:

import { mapState } from 'vuex'

// ...

<div v-for="row in gameGridAlias" class="row">

// ...

computed: mapState({
  gameGridAlias: state => state.GameGrid
})

More : https://vuex.vuejs.org/en/state.html#the-mapstate-helper

*Note: mapState is optional, but you can handle multiple stores with it and it's robust, i use it for all cases personally.

Edit: Don't use this.$store.state.GameGrid[y] or another this.$store.state vars but only mapState aliases to make it work correctly

Sign up to request clarification or add additional context in comments.

7 Comments

I get ReferenceError: mapState is not defined :/ Edit: thanks I'll try.
Edited, should be ok
Hmmm, I still cannot see visual changes while accessing this.cell on cell.vue, :(
Weird, are you sure the problem comes from the store ? I'm reflecting for another solution
You seems to use this.$store instead of the mapState aliases, try to wrap every variable into the mapState and use it, it will work, i'm sure of it
|
0
state.GameGrid[cell.y][cell.x].isRevealed = true;
add this
state.GameGrid =  Array.from(state.GameGrid); //force reflection by cloning array

It is not the most efficient solution but it only one that works for me

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.