Search code examples
vue.jsvuex

Better way of using vue instance in vuex


I just begun working with vuex, i came to a point where i had to use vue instance inside vuex. I was using a package called vue-toasted and to use to it inside vue application and wrote the following code inside main.js

import Toasted from 'vue-toasted';

const ToastedOptions = {
  position: 'bottom-center',
  duration: 1500,
  theme: 'bubble'
};

Vue.use(Toasted, ToastedOptions);

This worked fine inside .vue files. but was not working inside store.js.

Then i tried declaring same code inside store.js, which i didn't work either. I had to access the vue instance, so i came up with a couple of solutions:

  1. Passing the vue instance as payload to the actions
  2. Directly accessing vue instance through this._vm

Both pattern worked perfectly, but there must be a better way of doing that, a cleaner approach for clean code.


Solution

  • Vuex is a state management system, it's goal is to store your state (your data; employees, cars, application state, user details etc) Not manipulate the DOM. This is what you have vue for.

    As you see yourself, there is a ocean of ways to tackle this problem, but I think the best general way to fix this, would be to trigger back some "event" to Vue.

    An example could be to have an object in your state: toast

    const state = {
      toast: null,
      cars: [{...}, {...}, {...}]
    }
    

    Then when you are going to toast something, you can commit(mutate) the toast in the state to include some metadata for your real toast.

    const state = {
      toast: {
        title: 'An important message',
        options: {
          position: 'bottom-center',
          duration: 1500,
          theme: 'bubble'
        }
      },
      cars: [{...}, {...}, {...}]
    }
    

    In vue, you could for example have a watcher on the vuex toast state to wait for changes. Once the state.toast changes from null to an object, you can run the function to trigger the actual toast (in vue), then when the toast is done, you can clear the toast object from the state (telling vue there is no more toasts)

    Pseudo example vue file:

    import { mapState } from 'vuex';
    new Vue({
      computed: {
        ...mapState({
          toast: state => state.toast
        })
      },
      watch: {
        toast(toastData) {
          if (toastData === null) {
            return;
          }
          
          this.toastMessage(toastData);
        }
      },
      methods: {
        toastMessage(toastData) {
          this.toasted.show(toastData.title, toastData.options);
          window.setTimeout(this.resetToast, toastData.options.duration)
        },
        resetToast() {
          this.$store.commit('CLEAR_TOAST'); // mutation in vuex to set state.toast = null
        }
      }
    })