Use Vue.js plugin in Vuex Store module
Asked Answered
L

4

9

I am trying to use a Vue.js plugin inside of a Vuex Store module.

In a component, I am able to call it like this: this.$plugin(). However, in a module, this is not set. I thought Vue.$plugin() would work since I initialize the plugin with Vue.use(plugin) and Vue being a global variable, but it doesn't.

How do I reference the plugin from a module?

Lobule answered 22/11, 2017 at 16:49 Comment(5)
Is it your plugin? Do you have the code?Mehetabel
Here is the plugin: github.com/euvl/vue-notification Trying to use this.$notify(). But this should apply to all plugins with instance methods.Lobule
Using this is definitely not going to work, Vuex is not an instance of Vue. Looking over the plugin it doesn't look like it gives you an easy way to do what you want.Mehetabel
Here's a hacky way you might do this. But I think you would probably want to create a notifications array in Vuex state, and populate it when a notification is necessary, then in Vue watch the notifications queue and pop/display them as needed.Mehetabel
Thats pretty much how I ended up doing. window._app = new Vue({}); and _app.$notify({}); Thanks for the help though!Lobule
L
2

This question was answered by Bert in the example provided here: https://codesandbox.io/s/jp4xmzl0xy

    import Vue from 'vue'
    import App from './App'
    import Notifications from 'vue-notification'
    import Vuex from "vuex"
    Vue.use(Notifications)
    Vue.use(Vuex)
    
    let notifier = new Vue()
    
    
    const store = new Vuex.Store({
      state:{},
      actions:{
        notify(context, payload){
          notifier.$notify(payload)
        }
      }
    })
    
    
    /* eslint-disable no-new */
    new Vue({
      el: '#app',
      store,
      template: '<App/>',
      components: { App }
    })
Lobule answered 22/11, 2017 at 19:9 Comment(0)
N
3

The cleanest way I found is to import Vue in the store/module and then use the plugin via the Vue prototype.

import Vue from 'vue';

// .. in some logic
Vue.prototype.$dialog.alert('Something went wrong');
Nervine answered 30/7, 2020 at 21:2 Comment(2)
This is working, thanks. I was just wondering: don't we create a sort of "double import": vue imports the module and the module imports vue?Dulcine
@massimoi, I don't believe so. Circular imports would cause many issues, but it is common in Vue to import it in order to register plugins or use it's extended features.Nervine
L
2

This question was answered by Bert in the example provided here: https://codesandbox.io/s/jp4xmzl0xy

    import Vue from 'vue'
    import App from './App'
    import Notifications from 'vue-notification'
    import Vuex from "vuex"
    Vue.use(Notifications)
    Vue.use(Vuex)
    
    let notifier = new Vue()
    
    
    const store = new Vuex.Store({
      state:{},
      actions:{
        notify(context, payload){
          notifier.$notify(payload)
        }
      }
    })
    
    
    /* eslint-disable no-new */
    new Vue({
      el: '#app',
      store,
      template: '<App/>',
      components: { App }
    })
Lobule answered 22/11, 2017 at 19:9 Comment(0)
M
1

Pass in the vue instance as an argument

Another option is to pass the vue instance as an argument for your action.

// Vue component
{
  methods: {
    const vm = this
    this.$store.dispatch('someaction', { vm })
  }
}

// Store action
{
  someaction (context, { vm }) {
    vm.$dialog.alert('Something went wrong')
  }
}
Mazuma answered 25/4, 2021 at 8:34 Comment(3)
This seems like the best way to go. Are there caveats to this method like building for production or anything?Grin
@Grin There is no caveat besides the fact that you are passing in to vuex an instance of vue which is not ideal since it makes your code harder to maintain. Building this for production will work.Mazuma
Thanks. Yeah, ended up having to refactor the code because of this.Grin
T
0

There's a couple of other ways I've found. Honestly not sure which is the best though. I really don't like importing Vue and calling prototype methods. Seems like a complete antipattern and particularly difficult when it comes to testing using localVue as the actions have been coupled to global Vue.

  1. I'm pretty sure you're not supposed to do this but you can access the vue instance of the store from within an action using this._vm.$notify

  2. You can create a store plugin:

const notifyStore = (store) => {
  store.$notify = store._vm.$notify
}
  1. Create notify as a standalone module
import Vue from 'vue'

let notifier = new Vue()

export default notifier
  1. A combination of the two
import notifier from './notifier'

const notifyStorePlugin = (store) => {
  store.$notify = notifier.$notify
}

I'm not saying this is the definitive answer on this. I'm also very open to feedback and other suggestions.

Thermography answered 22/2, 2022 at 16:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.