21

I declare a global variable in the main.js of the Vue.js project.

Vue.prototype.$API = "myapihere"

And I want to use this from everywhere. and it's work properly by using this.$API.

But in Vuex it does not work.

console.log(this.$API);

Here this.$API is undefined.

How I use my $API in Vuex.

Rohit Nishad
  • 2,570
  • 2
  • 22
  • 32
  • 1
    `this` in vuex does not refer to vue instance that's why it doesn't work, try `this._vm`. – Chris Li Mar 02 '20 at 15:35
  • This doesn't work if you have actions, getters etc. in separate files. – secondman Jul 19 '21 at 19:28
  • @VinceKronlein this question is already answered. – Rohit Nishad Jul 20 '21 at 05:48
  • Yes but it's not correct. When actions, mutations, etc are imported from files, those files do not have access to `this._vm`, in my `actions.js` file `this` is undefined. – secondman Jul 20 '21 at 08:48
  • @VinceKronlein Maybe... I am not sure, I was writing a separate file for one logical component, in that one file I include all things (actions, state, mutations, etc) of that component. – Rohit Nishad Jul 20 '21 at 11:28
  • @RohitNishad Yes that's correct, in this situation `this` will point to the `Vuex.Store` instance in which your mutations or actions are in. But this isn't a likely scenario in a real world app. Your code would be a mess and virtually impossible to maintain when you have 200 actions and mutations in one file. So in the simplest of apps then yes this will work, but not really in a decent sized app. – secondman Jul 21 '21 at 06:31

5 Answers5

21

Vue 2 and Vuex 3 answer

In the store you can access the vue instance by accessing this._vm

const store = new Vuex.Store({
  mutations: {
    test(state) {
      console.log(this._vm);
    }
  }
});
Pierre Said
  • 3,660
  • 1
  • 16
  • 28
  • 4
    Note that this does **not work** in Vuex 4 (Vuex compatible with Vue 3). Even in Vuex 3 it was not part of the public API. Using not documented functions/properties is a recipe for problems in the future... – Michal Levý Aug 03 '21 at 15:45
  • 1
    This works with some caveats. _vm doesn't have access to other plugins, because it refers to the internal, separate Vue Instance that VueX uses for its store. If you use vuetify for example, it will not be available on this._vm, nor router. Only prototype modifications. Instead I used an IIFE in which I defined `const app = new Vue(/* settings */); store:$app = app` in order to provide my own reference to the Vue instance that renders my app after the store initialized its own. Then access the root instance from the store with `this.$app`. – Excalibaard Feb 14 '22 at 12:59
11

I'm using Vue 3 and Vue.prototype.$foo seems to have been removed for this version. I also found that in my version of VueX there is no this._vm.

I explored the Provide / Inject method which is recommended by the Vue 3 docs. This worked nicely for accessing globals from within my components, but I couldn't access them from within store.

The solution I went for was to use globalProperties on the Vue object and standard properties on store, and set them just before mounting the app.

main.js:

import store from './store/index';
import App from './App.vue';

// Load custom globals
import conf from '@/inc/myapp.config';

const app = createApp(App)
  .use(store);

// Register globals in app and store
app.config.globalProperties.$conf = conf;
store.$conf = conf;

app.mount('#app');

What I like about this is that I can access the globals in the same way in both store and components.

In a component:

export default {
  data() {
    return {
    };
  },
  created() {
    console.log( this.$conf.API_URL );
  },
}

...and you can access this.$conf.API_URL in the same way from actions, mutations and getters.

Once I'd found this solution I no longer needed access to the whole Vue instance from within store, but if you need it for some reason you can assign store.$app = app; in the same place in main.js.

Vilāsamuni
  • 143
  • 1
  • 6
  • I can't see any mention of `globalProperties` in the [Vue 2 docs](https://vuejs.org/v2/api/) so you'd have to read a bit about it and experiment, but I imagine the principle still stands. I'd be curious to know how you get on. – Vilāsamuni Sep 23 '21 at 08:56
  • Only works in js, you can't do that in typescript – CalibanAngel Nov 19 '21 at 09:51
  • This helped me a lot!!!! Works like a charm. Basically wherever you define global variables assign them to vue and router like this user did. – user6269972 Apr 16 '22 at 17:26
3

You have 2 approaches:

  1. Pass down the property (or even access the _vm property from inside Vuex) as an argument from a component

    methods: {
      this.$store.dispatch('someAction', this.$API)
    }
    
  2. Declare and export that same variable from another file and consume it from your main.js AND your Vuex file:

    // api.js
    export const API = "http://localhost:5000/api"
    
    // main.js
    import { API } from './api.js
    ...
    Vue.prototype.$API = API
    
    // store.js
    import { API } from './api.js
    
    // you can use API now!
    

Although I would personally lean towards the second, I would not store the API path in Vue at all as I'd rather have the api.js file as a service to perform all ajax calls and consume that file from where I need.

GMaiolo
  • 4,207
  • 1
  • 21
  • 37
2

use this._vm

here is why

by default when you access this in vuex store it will point store so it will output something like this

enter image description here

so after that, you see that there is something called _vm in store here it is enter image description here

so that _vm points to the vue component so to access it you will need to use this._vue

you can better create a getter of the vue instance like

const store = new Vuex.Store({
  getters: {
    vue(state) {
      return this._vm
    }
  }
});

//so you can use it across your store
store.getters.vue

//Note
//the above way of accessing getter works on non `namespaced` stores 
0

As of recently, under Vuex 4.* and Vue 3.*, this.$app hasn't been defined for the store object. Instead you have Vue Router defined as this.$router.

So for javascript, the way to get app in store would be like so:

The code would now be: router.app = app; and inside, say, an action: let app = this.$router.app;