Search code examples
vuexnuxt.jsvuetify.js

do not mutate vuex store state outside mutation handlers - Vuetify snackbar


I have a snackbar from Vuetify. It's in default.vue and the vuex store controls the v-model, message and color:

DefaultSnackBar.vue

<template>
  <v-container>
    <v-snackbar
      v-model="snackbarProperties.show"
      :color="snackbarProperties.color"
      timeout="7000"
      multi-line
    >
      {{ snackbarProperties.message }}

      <template v-slot:action="{ attrs }">
        <v-btn
          text
          v-bind="attrs"
          @click="hideSnackbar"
        >
          Close
        </v-btn>
      </template>
    </v-snackbar>
  </v-container>
</template>

<script>
import { mapActions } from "vuex";
import { mapGetters } from "vuex";
export default {
  methods :{
    ...mapActions("Snackbar",["showSnackbar","hideSnackbar"]),
  },
  computed: {
      ...mapGetters("Snackbar",["snackbarProperties"])
  },
}
</script>

Snackbar.js

export const state = () => ({
    message: "",
    color: "",
    show: false,
});

export const getters = {
    snackbarProperties: state => {
      return state;
    },
  
  }

export const mutations = {
    showSnackbar: (state, payload) => {
        state.message = payload.message;
        state.color = payload.color;
        state.show = true;
    },
    hideSnackbar: (state) => {
        state.message = "";
        state.color = ""
        state.show = false;
    },
}

export const actions = {
    showSnackbar({ commit }, payload) {
        commit('showSnackbar', payload)
    },
    hideSnackbar({ commit }) {
        commit('hideSnackbar')
    }
}

When I call showSnackbar({...}) the bar appears correctly with no errors, but when it disappears (timeout is reached) is get this error and everything crashes

do not mutate vuex store state outside mutation handlers

I think it's because when the bar disappears the component changes the value of the v-model it's attached to but I'm not sure how to work around this.


Solution

  • I found the answer from this vue forum:

    Use an action with the setTimeout code in it. Then in the timeout commit the mutation. Mutations should be synchronous which is why using a timeout in them is throwing a warning.

    I've updated Snackbar.js to suit:

    export const state = () => ({
        message: "",
        color: "",
        show: false,
    });
    
    export const getters = {
        snackbarProperties: state => {
          return state;
        },
      
      }
    
    export const mutations = {
        showSnackbar: (state, payload) => {
            state.message = payload.message;
            state.color = payload.color;
            state.show = true;
    
    
        },
        hideSnackbar: (state) => {
            state.message = "";
            state.color = ""
            state.show = false;
        },
    }
    
    export const actions = {
        showSnackbar({ commit }, payload) {
            commit('showSnackbar', payload)
            setTimeout(() => {
              commit('hideSnackbar')
            }, 500);
        },
        hideSnackbar({ commit }) {
            commit('hideSnackbar')
        }
    }