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.
Related
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
In vuex, I have this:
getByLessonId: state => _lessonId => {
return state.entities.filter(e => e.lesson.id === _lessonId);
},
In component:
// using as a method...
...mapGetters("assignment", { getAssignmentsByLessonId: "getByLessonId" }),
Later in the code, since the mapping returns the function, I need to call it like this?
// load this lessons assignments...
this.assignments = this.getAssignmentsByLessonId()(this.id);
// this is what i started with
// this.$store.getters["assignment/getByLessonId"](this.id)
It works, just not sure if there is a better way to do this? Or should I put mapGetters in the computed properties of the component?
Better put mapGetters (as long as mapState) in a computed section of a component. This is a recommended way to use several getters or props of a state because you have one place only to control getters and props in a component.
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'])
I'm setting an array in my data property through a computed function and it's working. But I wonder how is possible if I don't call it anywhere?
If I try to add a console.log in my function it doesn't print anything, but it's still setting my data, how is that possible?
My data:
data() {
return {
projects: []
};
},
My computed:
computed: {
loadedProjects() {
console.log("Hello there")
this.projects = this.$store.getters.loadedProjects
}
},
I expect that it doesn't run because I'm not calling, and if it is running(I don't know why) to print the console.log before to set my data. Any clarification?
Thanks:)
You're confusing computed props with methods. If you want to have a method like above that sets a data value of your vue instace, you should use a method, not a computed prop:
data() {
return {
projects: []
};
},
methods: {
loadProjects() {
console.log("Hello there")
this.projects = this.$store.getters.loadedProjects
}
}
This would get the value of this.$store.getters.loadedProjects once and assign it to your local projects value. Now since you're using Vuex, you probably want your local reference to stay in sync with updates you do to the store value. This is where computed props come in handy. You actually won't need the projects in data at all. All you need is the computed prop:
computed: {
projects() {
return this.$store.getters.loadedProjects
}
},
Now vue will update your local reference to projects whenever the store updates. Then you can use it just like a normal value in your template. For example
<template>
<div v-for='item in projects' :key='item.uuid'>
{{item.name}}
</div>
</template>
Avoid side effects in your computed properties, e.g. assigning values directly, computed values should always return a value themselves. This could be applying a filter to your existing data e.g.
computed: {
completedProjects() {
return this.$store.getters.loadedProjects.filter(x => x.projectCompleted)
},
projectIds() {
return this.$store.getters.loadedProjects.map(x => x.uuid)
}
}
You get the idea..
More about best practices to bring vuex state to your components here: https://vuex.vuejs.org/guide/state.html
Computed props docs:
https://v2.vuejs.org/v2/guide/computed.html
You should check Vue docs about computed properties and methods
and shouldn't run methods inside computed property getter
https://v2.vuejs.org/v2/guide/computed.html#Computed-Caching-vs-Methods
Instead of a computed property, we can define the same function as a method. For the end result, the two approaches are indeed exactly the same. However, the difference is that computed properties are cached based on their reactive dependencies. A computed property will only re-evaluate when some of its reactive dependencies have changed.
In my project , i have a shoppinglists Array to get displayed. When the component is mounted, the store is populated ( it' conatins only one array for the logged customer, fetched from the API db server... wo any problem)
On dissplay, I get the following message :
vue.esm.js?efeb:571 [Vue warn]: Property or method "shoppinglists" is not defined on
the instance but referenced during render. Make sure that this property is reactive,
either in the data option, or for class-based components, by initializing the
property.
See: https://v2.vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.
The shoppinglists property is defined as computed ...
computed: {
...mapGetters([ { shoppinglists: 'getShoppingLists' } ])
},
And the store contains the shoppinglists array
STATE
{
"shoppinglists":
[{"title":"Groceries","items":[{"text":"Bananas","checked":true},
{"text":"Apples","checked":false}],"id":1,"userId":1}],
"isAuthenticated":true,
"currentUserId":1
}
If I insert a prop declaration in data :
data: function () {
return {
shoppinglists: []
}
},
the warning disappear, but still theres is no list displayed..
what could be wrong ?
thanks for feedback
not exactly duplicated question, but not far from this one
It looks like you have mixed the two different options for mapGetters().
You can either write it like this:
import { mapGetters } from 'vuex'
export default {
// ...
computed: {
// mix the getters into computed with object spread operator
...mapGetters([
'doneTodosCount',
'anotherGetter',
// ...
])
}
}
Which maps this.doneTodosCount to this.$store.doneTodosCount and so on.
Or you could do it this way, which is probably what you want:
...mapGetters({
// map `this.doneCount` to `store.getters.doneTodosCount`
doneCount: 'doneTodosCount'
})
And for your example this becomes:
computed: {
...mapGetters({ shoppinglists: 'getShoppingLists' })
},
More documentation and source of the examples are at the bottom of this article.