10

I am creating a basic SPA, but it happens that the states I manage with Vuex and the mutations up there all right, but in each component that I want to use mapState and mapMutations I have to import them locally.

<script>
    import {mapState,mapMutations  } from 'vuex';
    export default{
        computed : mapState(['isLoggedIn']),
        methods: {
            ...mapMutations(['logout'])
        }
    }
</script>

This is the correct way to do it? Or how can I declare them globally and avoid importing in each component so that it is as follows?

<script>   

    export default{
        computed : mapState(['isLoggedIn']),
        methods: {
            ...mapMutations(['logout'])
        }
    }
</script>
DarkFenix
  • 706
  • 1
  • 13
  • 34
  • 2
    I think this is the correct way to do it. You could do `window.mapState = mapState` but that's NOT a good practice. – Herman Starikov Apr 09 '18 at 20:31
  • And if you are still seeing `mapState is not defined`, try doing the assignment inside `App.vue` instead of `main.js` – phil294 Jan 08 '20 at 19:41

1 Answers1

9

Quick solutions

The Vuex helpers like mapMutations etc. returns an object populated with functions which assumes that this.$store is a Vuex store.

Store service

If you need to use the store in vanilla JS and you don't want to expose the store module everywhere, you could define a service module.

import { mapActions } from 'vuex';
import $store from '@/store';

/**
 * Simple mapping of the Vuex store UI module.
 * @module services/ui
 * @property {Function} pushMessage
 */
export default Object.assign({
    $store,
}, mapActions('ui', ['pushMessage']));

Now, using it is as simple as importing the service module.

import ui from './services/ui';

// triggers the `pushAction` on the ui namespaced store module
ui.pushMessage({ content: 'whatever' });

Vue mixin

To have default computed and methods on a Vue component, you can create a simple mixin to import in specific components.

import { mapState, mapMutations } from 'vuex';

export default {
    computed : mapState(['isLoggedIn']),
    methods: mapMutations(['logout'])
}

Then, use the mixin in a component.

<script>
import mixin from './mixin';

export default {
  mixins: [mixin],
  data() {/* ... */},
  // etc.
}
</script>

Global mixin

If you really want each component to have this default mixin without having to explicitly define it, use a global mixin.

import Vue from 'vue';
import { mapState, mapMutations } from 'vuex';

export const mixin = {
    computed : mapState(['isLoggedIn']),
    methods: mapMutations(['logout'])
};

Vue.mixin(mixin);

Personally, as a standard, I never map the state or mutations.

I only map getters and actions so my components don't need to know the state structure and that an action is async or not. I see getters and actions as the public API of a Vuex store (or any similar store, like Redux).

I also only map the relevant data. Components responsibility is to interact with the user of the app, displaying and handling events and nothing more. If all your components need the user object, maybe they're doing too much and that logic should probably be moved elsewhere, like in an action.

See more on Vue communication

tony19
  • 125,647
  • 18
  • 229
  • 307
Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
  • Thank you very much for the alternatives, just a final question. What is the best option for you? – DarkFenix Apr 09 '18 at 21:47
  • @dark i prefer to be explicit, so I use services with moderation and declare explicitly the actions and getters on my component. – Emile Bergeron Apr 09 '18 at 21:52
  • Thank you very much, I will try. regards – DarkFenix Apr 09 '18 at 22:30
  • In my case, I keep the logged in user in Vuex, so I have a global mapState to access the User object in every component. But as @EmileBergeron suggested, in general its better to keep fine grained control on the stuff available on each Component – chesscov77 Mar 26 '19 at 15:22
  • @Juan even in this case, I'd only map the user data to the specific components who need him. If every components need the user, it's possibly that your components are responsible for too much and some logic could possibly done elsewhere, like in actions, etc. – Emile Bergeron Mar 26 '19 at 15:37
  • Also, as a standard, I never map the state, I only map _getters_ and _actions_ so my components don't need to know the state structure and that an action is async or not. – Emile Bergeron Mar 26 '19 at 15:39
  • I dont think this answers the question at all. OP asked for a way to have `mapActions` be a global function (and thus get rid of the repeated imports everywhere). Not sure what I am misunderstanding or why he accepted this. – phil294 Jul 20 '19 at 13:14
  • 1
    @Blauhirn OP asked if what he was doing was standard and if there was a way to *avoid importing the helpers everywhere*. The thing is, it's a really bad practice to make anything global if not necessary, but if you really want that, just `window.mapActions = mapActions`. I believe my answer is better than that, by showing 3 good ways to do it. – Emile Bergeron Jul 20 '19 at 14:36