Skip to content
Advertisement

“Do not mutate vuex store state outside mutation handlers” error even after using computed var for prop

With the following component, I am getting an Error: [vuex] do not mutate vuex store state outside mutation handlers. error:

<template>
  <div>
    <v-data-table
      :headers="headers"
      :items="items"
      :search="search"
      :key="tableKey"
      :pagination.sync="pagination"
      disable-initial-sort
      rowKey
    >
    <template slot="items" slot-scope="props">
      <tr @click="clicked(props.item)" :class="{'secondary': props.item[rowKey]===selectedCode}">
        <td v-for="header in headers" :key="header.value">
          <BaseTableColumn
            :item="props.item"
            :index="header.value"
            :format="header.format"
          />
        </td>
      </tr>
    </template>
  </v-data-table>
  </div>
</template>

<script>
export default {
  name: 'BaseTable',
  props: {
    headers: Array,
    items: Array,
    search: String,
    tableKey: String,
    rowKey: String,
  },
  data: () => ({
    pagination: {
      rowsPerPage: 10,
      totalItems: -1,
    },
    selectedCode: -1,
  }),
  components: {
    BaseTableColumn: () => import('@/components/base/BaseTableColumn'),
  },
  methods: {
    clicked(row) {
      window.scrollTo(0, 0);
      this.selectedCode = row[this.rowKey];
      this.$set(row, 'selected', true);
      this.$emit('rowClick', row);
    },
    highlightFirst(items) {
      this.selectedCode = this.items[0][this.rowKey];
      this.$set(this.items[0], 'selected', true);
    },
  },
  updated() {
    if (this.selectedCode === -1 && (typeof this.items === 'object') && this.items.length > 0) {
      this.highlightFirst(this.items);
    }
  },
};
</script>

For reference, here is headers.js:

const headers = [
  {
    text: 'Tenant Code',
    value: 'code',
  },
  {
    text: 'Tenant ID',
    value: 'name',
  },
];

export default headers;

and BaseTableColumn.vue:

<script>
export default {
  name: 'BaseTableColumn',
  props: {
    format: Function,
    item: Object,
    index: String,
  },
  methods: {
    getText() {
      return this.item[this.index];
    },
  },
  render(createElement) {
    if (this.$props.format) {
      return this.$props.format(this.item, this.index, createElement);
    }
    return createElement('div', this.getText());
  },
};
</script>

The issue happens here:

  this.$set(this.items[0], 'selected', true);

However, if I follow the docs like so:

<template>
  <div>
    <v-data-table
      :headers="headers"
      :items="tableRows"
      :search="search"
      :key="tableKey"
      :pagination.sync="pagination"
      disable-initial-sort
      rowKey
    >
...
</template>

<script>
export default {
  name: 'BaseTable',
  props: {
    headers: Array,
    items: Array,
    search: String,
    tableKey: String,
    rowKey: String,
  },
...
  computed: {
    tableRows() {
      const rows = [...this.items];
      return rows;
    },
  },
...
  methods: {
...
    highlightFirst(items) {
      this.selectedCode = this.items[0][this.rowKey];
      this.$set(this.tableRows[0], 'selected', true);
    },
  },
  updated() {
    if (this.selectedCode === -1 && (typeof this.tableRows === 'object') && this.tableRows.length > 0) {
      this.highlightFirst(this.tableRows);
    }
  },
};
</script>

I still get the errors, specifically in the updated() hook and the highlightFirst() method, even though I’m not referencing or mutating a prop. What else do I need to change to get rid of this error?

Advertisement

Answer

The way I eventually solved this problem was to emit an event and use the row value in the parent component:

clicked(row) {
  window.scrollTo(0, 0);
  this.selectedCode = row[this.rowKey];
  this.$emit('rowClick', row);
},

However, to @Jesper’s point above, since then, I have been using Object.assign() in cases like this where I need to break the link to Vuex.

User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement