Vuex modules namespacing references - how to mapState correctly [duplicate] - vue.js

I must be missing something. How can I use vuex mapState with multiple modules?
As far as understand, besides passing an object as argument, namespaced mapState can take two arguments: namespace and an array of object names denoting the members of modules. Like this
// an imcomplete vue
export default {
computed: mapState('user', ['addresses', 'creditCards'])
};
But what if i'd like to add objects from a second namespace to computed? e.g. vendor like this:
mapState('vendor', ['products', 'ratings'])
Currently I am merging both mapState like this:
let userMapState = mapState('user', ['addresses', 'creditCards']);
let vendorMapState = mapState ('vendor', ['products', 'ratings']);
let mergedMapStates = Object.assign({}, userMapState, vendorMapState);
And then:
// an imcomplete vue
export default {
computed: mergedMapStates
};
It works, but it's hardly the right way to do it. Or is it?

Use the spread operator:
computed: {
...mapState('user', ['addresses', 'creditCards']),
...mapState('vendor', ['products', 'ratings'])
}

This is from the vuex docs, you can do it all within one ...mapState({}). Documentation
computed: {
...mapState({
a: state => state.some.nested.module.a,
b: state => state.some.nested.module.b
})
},
Edit 2019
You can also pass a path to your nested module and make the module references cleaner (thanks #gijswijs)
computed: {
...mapState('some/nested/module', {
a: state => state.a,
b: state => state.b
})
},

You can try this if you have no too many namespaces:
...mapState({
userAddresses: 'user/addresses',
userCreditCards: 'user/creditCards'
vendorProducts: 'vendor/products',
vendorRatings: 'vendor/ratings',
})

You could also use Object.assign like this. Similar to your current solution but a bit cleaner.
computed: Object.assign(
mapState('user', ['addresses', 'creditCards']),
mapState('vendor', ['products', 'ratings']
)

Make use of spread operator to access multiple module State values
...mapState('user', {
isLoggedIn: ({ activeUser }) => !!activeUser?.id
}),
...mapState('quizzes', ['getCategories'])

Related

How to use `mapGetters` in the computed section only, without passing it to data ? And what name should I pass to the set?

This is a screenshot from another question about mapGetters
Link to the question I took the screen from
In Vue.js I saw an answer to a post.
It said :
In your Component
computed: {
...mapGetters({
nameFromStore: 'name'
}),
name: {
get(){
return this.nameFromStore
},
set(newName){
return newName
}
}
}
And I wonder why newName is a "new" name ? And also what it looks like to call the getter in the template html section. Do we use the nameFromStore like a data in the template ?
I tried to see how getters are used but what I found didn't look like this structure. The things I found looked like someone using a value in data that returns this.$store.getters.nameFromStore but I don't want to use the data and do it all in the computed instead like the picture I attached if someone can please help me ?
If you simply want to use mapGetters to access data store in vuex state you can do it as you have it above, without the get/set computed. I'm not sure what the intention of that get/set computed property was but it doesn't look like it would work as expected.
Try this:
// vuex index.js
// ...
getters: {
getAnimals: state => {
return state.items.filter(i => i.type === 'animal');
}
}
// your component.vue
import { mapGetters } from 'vuex'
export default {
// ...
computed: {
...mapGetters(['getAnimals']) // access using this.getAnimals
// or
...mapGetters({ animals: 'getAnimals' }) // access using this.animals
}
}
The bennefit to using it this way is being a computed property, when the items change in vuex state, they will be recomputed, and your component will react to this change. Hopefully this is a clear explanation.
The vue docs:
https://vuex.vuejs.org/guide/getters.html#method-style-access

Alias a single Vue getter in mapGetters

I have a vuex module with getters. I am using this module's getters in a vue component:
...
computed: {
...mapGetters('myCoolModule', ['isActive', 'someOtherGetter', 'yetAnotherGetter']),
}
...
I have other vuex modules that have an isActive getter, so I would like to alias it here. I am familiar with the object syntax, i.e.,
...
computed: {
...mapGetters('myCoolModule', { myCoolModuleIsActive: 'isActive', someOtherGetter: 'someOtherGetter', yetAnotherGetter: 'yetAnotherGetter' }),
}
...
However, I do not need to alias 'someOtherGetter' or 'yetAnotherGetter', and the object syntax seems to require that I do just that.
Is there a syntax to use with mapGetters such that I can alias only one of the getters?
What about using it twice ?
computed:
{
...mapGetters('myModule', {
myCoolModuleIsActive: 'isActive',
}),
...mapGetters('myModule', ['someOtherGetter', 'yetAnotherGetter']),
}
And why not namespacing your Vuex modules ? Thus name collisions like this will be avoided.

Vuex name function with namespaced in getters

Hi I need create function which have payload.
In Vuex I created:
const getters = {
[GettersTeam.GET_TEST](state) {
return state.teams;
},
[GettersTeam.GET_TEAM]: state => id => {
console.log("Run function!");
console.log(id);
return state.teams;
},
};
Next I using this function in component:
mounted() {
this.GET_TEAM(1);
},
methods: {
...mapGetters('TeamModule', [GettersTeam.GET_TEAM]),
},
Function this.GET_TEAM(1) nothing return. I thing the problem is with the name function [GettersTeam.GET_TEAM], but I don't know how I can named function with namespaced. Function this.GET_TEST() work correctly.
EDIT:
I moved function from methods to computed.
computed: {
...mapGetters('TeamModule', {
teamList: [GettersTeam.GET_TEAM],
}),
},
<template>
<div>
teamList: {{ teamList }}
</div>
</template>
But when I try using teamList in template Vue returned me this:
teamList: function (id) { console.log(id); return state.teams; }
You need to put mapGetters in your computed section, not methods:
computed: {
...mapGetters('TeamModule', [GettersTeam.GET_TEAM]),
},
https://vuex.vuejs.org/guide/getters.html#the-mapgetters-helper
That may seem slightly counter-intuitive given you're invoking it as a method but from the component's perspective it's still just a property. It just so happens that the property returns a function.
Update:
Based on the new question...
In your template you've got {{ teamList }}. That will be grabbing the value of the property this.teamList.
The property this.teamList is a computed property, so Vue will call the defining function behind the scenes. That defining function is created by mapGetters but it effectively just calls the store getter, passing it the relevant state object.
You've defined the getter like this:
[GettersTeam.GET_TEAM]: state => id => {
Ignore the bit in the brackets, that isn't important here. The key bit is the state => id => { part. There are two functions here, one being returned by the other.
Effectively it is equivalent to this:
[GettersTeam.GET_TEAM] (state) {
return function (id) {
console.log("Run function!");
console.log(id);
return state.teams;
}
}
So when you access the computed property you're just going to be invoking that outer function. It'll return the inner function, which is what you're seeing your template.
To get the value returned by the inner function you'd need to invoke it. e.g.:
{{ teamList(1) }}
I would also note that your current implementation of the getter just ignores the id. It isn't clear exactly what you're trying to do but I assume you're intending to implement a search based on the id to find a particular entry within state.teams.
Made a Codepen for you.
Your mapGetters call should be mapGetters([GettersTeam.GET_TEAM]) and your this.GET_TEAM(1); call should be this[GettersTeam.GET_TEAM](1); instead.

How to maintain similar variable name in component & in state - VUEJS?

I'm going to use a similar variable in state and in a component as well like below,
store.js
{
export default new Vuex.Store({
state: {
title: 'Component Block'
}
})
}
ComponentA.vue
export default {
data() {
return {
title: ''
}
},
computed: {
...mapState(['title'])
}
}
Is there any way to differentiate either state variable or component variable without changing the variable names causing of similar name?
Thanks,
You can't have a shared name across data/methods/computed properties at the moment in Vue.
If you are wedded to using a data property call title, you can key your mapState:
...mapState({
titleFromStore: 'title'
})
But it's worth considering why we can't use the same name. It would add a layer of confusion to your code. When referring to this.title, which one would you be referring to? This limit is there for a good reason, I'd recommend renaming the data property.

Vuex State - Array empty

My Problem is, that the state-variable "genreRankings" in "store.js" is never updating.
Can somebody tell me why?
I'm accessing the Store via my Component as follows:
saveMovie (item) {
this.$store.dispatch('addMovie', item).then(x => {
console.log(this.$store.state.savedMovies)
this.$store.commit('update_genreRankings', Util.getGenreRankings(this.$store.getters.savedMovies))
})
},
removeMovie (item) {
this.$store.dispatch('removeMovie', item).then(x => {
this.$store.commit('update_genreRankings', Util.getGenreRankings(this.$store.getters.savedMovies))
})
},
Here is store.js (https://gist.github.com/oaltena/ccc70c06c29a1d9af6aa3234aba79518) and Util.js (https://gist.github.com/oaltena/67b8431199e9a6d74681c04d9183e630).
When i access the "genreRankings" via VueDevTools the array is always empty.
Help, please! :-)
Try "replacing" the state with a new array :
state.savedMovies = state.savedMovies.concat(object)
As written in the Vuex documentation, the state of Vuex store follows the same rules as the state in the components : https://vuex.vuejs.org/guide/mutations.html#mutations-follow-vue-s-reactivity-rules
PS: it's pretty ugly to call mutations directly from the components, use mapActions to map your actions in your components, then call commit from the action. You'll make a more maintenable code.
Try replacing this:
update_genreRankings (state, object) {
state.genreRankings = object
}
with this:
update_genreRankings (state, object) {
Vue.set(state, 'genreRankings', object)
}
Reference: https://v2.vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats