Home > Back-end >  Is there a way to encapsulate Vuex store inside Vue plugin (its install function)?
Is there a way to encapsulate Vuex store inside Vue plugin (its install function)?

Time:01-29

  • I have a plugin and this plugin uses Vuex
// plugin.js
import Vuex from "vuex";
import store from "./store.js";

export default {
  install(Vue, options) {
    const storeInstance = new Vuex.Store(store);
    Vue.prototype.$store = storeInstance;
  }
};
  • And in that plugin I import a store object.
// store.js
export default {
  actions: {
    SOME_RANDOM_ACTION({ state, commit }) {
      console.log("some random action");
    }
  }
};

Dispatching actions and using state is fine and works as expected.

But when I add this plugin to another Vue instance that uses vuex, store object re-initializes with new state.

// index.js
import Vue from "vue";
import Vuex from "vuex";
import App from "./App.vue";
import plugin from "./plugin.js";

Vue.use(Vuex);
Vue.use(plugin);

new Vue({
  // WARN when i uncomment this next line of code Vuex gets re-initialized with new object
  // store: new Vuex.Store({ state: { hello: "hix" } }),
  components: {
    App
  }
}).$mount("#app");

When you uncomment store initialization, store that was defined in the plugin is now not available.

Currently, I have these solutions in mind:

  1. Export my plugin store object to index.js main app, and use this store as a module.
  2. Use some other state management.

Is there a way to use Vuex inside my plugin?

https://codesandbox.io/s/vibrant-sanne-67yej?file=/src/main.js:0-371

CodePudding user response:

Vuex plugin uses store option to assign store instance to Vue.prototype.$store, similarly to your own plugin.

If the intention is to use multiple stores, their names shouldn't collide. The key is to name your store object inside plugin something other than $store

Vue.prototype.$myPluginStore = storeInstance;

But this still doesn't encapsulate $myPluginStore inside the plugin, as it is accessible within the app.

// App.vue

computed: {
    appState() {
      return this.$store.state;
    },
    pluginState() {
      return this.$myPluginStore.state; // this is now accessible within the main app
    }
}

It would be a reasonable solution to allow a store to be used as a module of existing store instead of creating a new store, but only when used within one app and not when used as a plugin for a package.

The main problem is that default store instance ($store) can make use of Vuex helpers - mapGetters, etc.

CodePudding user response:

You can take advantage of the install method exposed by the plugin to get access to the store - which should be accessible from your other component.

One possible solution is to register your store in the index.js like:

import Vue from "vue";
import App from "./App.vue";
import store from "./store";
import plugin from "./plugin";

Vue.use(plugin);

new Vue({
  store,
  components: {
    App
  }
}).$mount("#app");

You can then expose $doStuff() and get access to $store in the plugin.js

export default {
  install(Vue) {
    Vue.prototype.$doStuff = function (payload) {
      this.$store.dispatch("SOME_RANDOM_ACTION", payload);
    };
  }
};

The store instance is accessible from your plugin or all the other components.

You can see a working sample here

  •  Tags:  
  • Related