How to access vue instance in Vuex
Asked Answered
K

5

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.

Kerri answered 2/3, 2020 at 15:29 Comment(6)
this in vuex does not refer to vue instance that's why it doesn't work, try this._vm.Bracci
This doesn't work if you have actions, getters etc. in separate files.Ebullition
@VinceKronlein this question is already answered.Kerri
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.Ebullition
@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.Kerri
@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.Ebullition
F
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);
    }
  }
});
Fecal answered 2/3, 2020 at 15:35 Comment(2)
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...Franglais
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.Coraleecoralie
G
13

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.

Gagarin answered 23/4, 2021 at 12:8 Comment(3)
I can't see any mention of globalProperties in the Vue 2 docs 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.Colfin
Only works in js, you can't do that in typescriptLeone
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.Delldella
D
4

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.

Delusion answered 2/3, 2020 at 15:43 Comment(0)
M
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 
Mix answered 15/9, 2020 at 9:22 Comment(0)
M
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;

Millner answered 6/2, 2022 at 15:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.