简体   繁体   中英

Error:[vuex] do not mutate vuex store state outside mutation handlers vuex (nuxt.js)

I've already searched what causes this error message to appear but could not really get my head around it in my code. I'm using Nuxt.js with Vuex. I just can't see where am i modifying the store without mutation. Can someone please tell me what am i doing wrong? This error message appears when i pick some date from the date picker component. This solution works as intended, it's just the error message that bugs me and i dont really want to solve it by turning off the strict mode for store.

Component.vue

<template>
  <v-col class="chart">
    <v-card>
      <v-card-title>Daily beta trend</v-card-title>
      <v-row>
        <v-col cols="4">
          <b-form-group label="From" class="ml-3">
            <b-form-datepicker id="datepicker-from" v-model="chartDataFrom" class="mb-2" />
          </b-form-group>
        </v-col>
        <v-col cols="4">
          <b-form-group label="To">
            <b-form-datepicker id="datepicker-to" v-model="chartDataTo" class="mb-2" />
          </b-form-group>
        </v-col>
        <v-col cols="4">
          <b-form-group label="OS Version" class="mr-3">
            <b-form-select v-model="selectedOS" :options="OSVersions">
              <template #first>
                <b-form-select-option :value="null" disabled>
                  -- Please select OS version --
                </b-form-select-option>
              </template>
            </b-form-select>
          </b-form-group>
        </v-col>
      </v-row>
      <v-skeleton-loader
        v-if="$fetchState.pending"
        class="mx-auto"
        max-width="300"
        type="card"
      />
      <p v-else-if="$fetchState.error">
        An error occurred :(
      </p>
      <div v-else>
        <Chart :data="chartData" />
      </div>
    </v-card>
  </v-col>
</template>

<script>
import Chart from '~/components/Trends/Charts/Chart'
export default {
  name: 'BetaTrend',
  components: {
    Chart
  },
  async fetch () {
    await this.$store.dispatch('beta_trend/getChartData')
  },
  fetchOnServer: false,
  computed: {
    chartData: {
      get () {
        return this.$store.state.beta_trend.chartData
      },
      set (data) {
        this.$store.commit('beta_trend/SET_CHART_DATA', data)
      }
    },
    chartDataFrom: {
      get () {
        return this.$store.state.beta_trend.from
      },
      set (value) {
        this.$store.commit('beta_trend/SET_FROM', value)
        this.$fetch()
      }
    },
    chartDataTo: {
      get () {
        return this.$store.state.beta_trend.to
      },
      set (value) {
        this.$store.commit('beta_trend/SET_TO', value)
        this.$fetch()
      }
    },
    OSVersions: {
      get () {
        return this.$store.state.beta_trend.os
      }
    },
    selectedOS: {
      get () {
        return this.$store.state.beta_trend.selectedOs
      },
      set (value) {
        this.$store.commit('beta_trend/SET_SELECTED_OS', value)
        this.$fetch()
      }
    }
  }
}
</script>

<style scoped>

</style>

the store is defined like this:

export const state = () => ({
  chartData: [],
  from: null,
  to: null,
  os: [
    'All',
    '1803',
    '19042'
  ],
  selectedOs: null
})

export const mutations = {
  SET_CHART_DATA (state, data) {
    state.chartData = data
  },
  SET_FROM (state, from) {
    state.from = from
  },
  SET_TO (state, to) {
    state.to = to
  },
  SET_SELECTED_OS (state, os) {
    state.selectedOs = os
  }
}

export const actions = {
  async getChartData ({ commit, state }) {
    const data = await this.$axios.$get('api/frontend/trend/XXX', {
      params: {
        from: state.from,
        to: state.to,
        os: state.selectedOs
      }
    })
    commit('SET_CHART_DATA', data)
    if (state.from === null) {
      commit('SET_FROM', data.dates[0])
    }
    if (state.to === null) {
      commit('SET_TO', data.dates[data.dates.length - 1])
    }
  }
}

I fix this issue by using Lodash's cloneDeep method on the get() of my computed option. I do have the state that is deep copied, this way it prevents any mutation of the actual object, and can therefore be modified by the set() in the same way.

The only needed thing is

import { cloneDeep } from 'lodash-es'

export default {
[...]

chartData: {
  get () {
    return cloneDeep(this.$store.state.beta_trend.chartData)
  },
  [...]
},

PS: also worth mentioning that JSON.parse(JSON.stringify(object)) is not recommended: https://flaviocopes.com/how-to-clone-javascript-object/#wrong-solutions

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM