I have a Vue component that maps in state, mutations, actions, and getters from a Vuex store.
import {mapState, mapMutations, mapActions, mapGetters} from 'vuex'
export default {
name: 'DefaultLayout',
computed: {
...mapState({
settings: (state) => state.settings,
language: (state) => state.language
}),
...mapState([
'changeRouteTo'
]),
...mapGetters([
'isLoggedIn'
])
}
...
The problem is, I cannot get ...mapGetters to work with the explicit syntax like I do with the first instance of ...mapState above.
I've tried
...mapGetters({
isLoggedIn: (state) => state.getters.isLoggedIn
})
and
...mapGetters({
isLoggedIn: (state) => state.isLoggedIn
})
and
...mapGetters({
isLoggedIn: (state) => this.$store.getters.isLoggedIn
})
But only
...mapGetters([
'isLoggedIn'
])
seems to work.
To use an object in ...mapGetters the syntax is as follows:
...mapGetters({
isLoggedIn: 'isLoggedIn'
})
where the key is the name you want the getter to map to and the value is the name of the getter as a string
with mapGetters you should use getters to access some slice of the state for example in your store you will have something like this
const state = {
isLoggedIn:''
}
const getters = {
isLoggedIn(state) {
return state.isLoggedIn
}
}
export default {
state,
getters
}
and in your component you can access the isloggedIn property like this
computed: {
...mapGetters(['isLoggedIn'])
},
and now you have access to isLoggedIn property
because mapGetters gives access to the gitters the get functions that returns a slice of the store you dont have to rewrite the get function and pass the state to it that logic you should do it the in the getters this is there purpose
The above answers were all correct, though they don't answer the question "why"?
So the docs don't answer it either - it's a shame.
Let me give you my take:
VueX getters should already do whatever you need.
You see, VueX is meant for large applications. As such, there's a high chance the state or the state that is derived from the base state(getters) will be used in more than one place.
Getters already have access to the VueX state (as they are derived from the state!), they already have access to the other VueX getters too!
I'd say, if you find yourself needing to manipulate the getter, just create another getter that does just that - and simply import it.
Related
I am trying to filter out my user by using getters in 2 different files. How can these both be used together correctly?
users.js
getAllUsersById(state) {
return state.userIds.map(id => state.UserById[id])
}
auth.js
getAuthUser(state) {
return state.user
},
So getAuthUser from auth.js should be implemented inside users.js and get filtered out from getAllUsers.
,
To access Vuex getters from another getter you have to pass store.getters to it:
auth.js
[...]
getters: {
getAuthUser: state => state.user
}
[...]
users.js
[...]
getters: {
getAllUsersById: (state, getters) => state.userIds.map(id => state.userById[id]).filter(user => user.id != getters.getAuthUser.id)
}
[...]
Since all vuex modules should be menaged by the same Vuex store no import is needed: providing (state, getters) as an argument of getAllUsersById gives the method access to all the getters inside Vuex in addition of the state.
i'm new to Vue and Nuxt and i'm building my first website in Universal mode with these framework.
I'm a bit confused on how the store works in nuxt, since following the official documentation i can't achieve what i have in mind.
In my store folder i have placed for now only one file called "products.js", in there i export the state like this:
export const state = () => ({
mistica: {
id: 1,
name: 'mistica'
}
})
(The object is simplified in order to provide a cleaner explanation)
In the same file i set up a simple getter, for example:
export const getters = () => ({
getName: (state) => {
return state.mistica.name
}
})
Now, according to the documentation, in the component i set up like this:
computed: {
getName () {
return this.$store.getters['products/getName']
}
}
or either (don't know what to use):
computed: {
getName () {
return this.$store.getters.products.getName
}
}
but when using "getName" in template is "undefined", in the latter case the app is broken and it says "Cannot read property 'getName' of undefined"
Note that in the template i can access directly the state value with "$store.state.products.mistica.name" with no problems, why so?
What am i doing wrong, or better, what didn't i understand?
Using factory function for a state is a nuxt.js feature. It is used in the SSR mode to create a new state for each client. But for getters it doesn't make sense, because these are pure functions of the state. getters should be a plain object:
export const getters = {
getName: (state) => {
return state.mistica.name
}
}
After this change getters should work.
Then you can use the this.$store.getters['products/getName'] in your components.
You can't use this.$store.getters.products.getName, as this is the incorrect syntax.
But to get simpler and more clean code, you can use the mapGetters helper from the vuex:
import { mapGetters } from "vuex";
...
computed: {
...mapGetters("products", [
"getName",
// Here you can import other getters from the products.js
])
}
Couple of things. In your "store" folder you might need an index.js for nuxt to set a root module. This is the only module you can use nuxtServerInit in also and that can be very handy.
In your products.js you are part of the way there. Your state should be exported as a function but actions, mutations and getters are just objects. So change your getters to this:
export const getters = {
getName: state => {
return state.mistica.name
}
}
Then your second computed should get the getter. I usually prefer to use "mapGetters" which you can implement in a page/component like this:
<script>
import { mapGetters } from 'vuex'
export default {
computed: {
...mapGetters({
getName: 'products/getName'
})
}
</script>
Then you can use getName in your template with {{ getName }} or in your script with this.getName.
how can i use vuex state and use to methods property of components?
I have a state "currentThreadId" but i want to use that state in methods?
what i struggle is i can get the "currentThreadId" in my vuex state using computer property. but i don't know how to pass it to methods. i want to use that id for axios request.
messagesServices.attachEstimate({message_id}).then(response => {
console.log(response);
});
all i want is the way how to get the id and use to methods property.
As described here there are multiple ways to access state in your components. I'd suggest using the mapState helper with the spread operator. For example:
<script>
import { mapState } from 'vuex';
export default {
computed: {
...mapState([
'currentThreadId',
]),
},
methods: {
someMethod() {
console.log(this.currentThreadId)
},
},
};
</script>
How can I watch for store values changes when params are used? I normally would do that via a getter, but my getter accepts a param which makes it tricky as I've failed to find documentation on this scenario or a stack Q/A.
(code is minimized for demo reasons)
My store.js :
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
let report = {
results: [],
};
export const store = new Vuex.Store({
state: {
broken: Object.assign({}, report),
},
results: (state) => (scan) => {
return state[scan].results
},
});
vue-component.vue :
computed: {
...mapGetters([
'results',
]),
watch: {
results(){ // How to pass the param ??
// my callback
}
So basically I would like to find out how to pass the param so my watch would work.
In my opinion, there is no direct solution for your question.
At first, for watch function, it only accept two parameters, newValue and oldValue, so there is no way to pass your scan parameter.
Also, your results property in computed, just return a function, if you watch the function, it will never be triggered.
I suggest you just change the getters from nested function to simple function.
But if you really want to do in this way, you should create a bridge computed properties
computed: {
...mapGetters([
'results',
]),
scan() {
},
mutatedResults() {
return this.results(this.scan);
},
watch: {
mutatedResults() {
}
}
}
When I put this in my Vue component ...
// using store getter
computed: {
authenticated() {
return this.$store.getters.authenticated
}
}
... it works. The value for authenticated is reactive and the computed property returns true when the value in the vuex store is true.
This should work ... (and would be the right way according to the docs)
// using store state
computed: {
authenticated() {
return this.$store.state.authenticated
}
}
... but doesn't. The computed property is always false.
It doesn't even work on initial state, so I guess it has nothing to do with the action or mutation. The vuex store holds the correct values in the state and the getters (Firefox Vue DevTools).
My store looks like this:
const state = {
authenticated: authenticate.isAuthenticated(),
};
const getters = {
authenticated () {
return state.authenticated
}
};
const mutations = {
isAuthenticated (state, isAuthenticated) {
state.authenticated = isAuthenticated
}
};
So, it works with store getters but not with store state. Afaik the store state should be reactive as well.
Any idea what I might be doing wrong?
More as an aside to this discussion, vuex offers the mapGetters, mapState, mapActions, and mapMutations helper functions.
In the case of the authenticated getter, you would map it like:
import { mapGetters } from 'vuex
computed: {
...mapGetters({
authenticated: 'authenticated'
})
}
Helps to keep your code clean and concise, imo.
Assuming you construct your Vuex.Store as I do below, the computed works as expected using either state.authenticated or getters.authenticated.
The mutations section made no difference, so I took it out to make things minimal.
As Bert noted, your getter should take state as a parameter; otherwise, it is using the declared const, which is the same thing in this case, but deceptive to read.
const authenticate = {
isAuthenticated() {
return true;
}
};
const state = {
authenticated: authenticate.isAuthenticated()
};
const getters = {
authenticated (state) {
return state.authenticated;
}
};
const store = new Vuex.Store({
state,
getters
});
new Vue({
el: '#app',
store,
computed: {
authenticated() {
return this.$store.state.authenticated;
}
}
});
<script src="//unpkg.com/vue#latest/dist/vue.js"></script>
<script src="//unpkg.com/vuex#latest/dist/vuex.js"></script>
<div id="app">
Anything? {{authenticated}}
</div>
const state = {
authenticated: authenticate.isAuthenticated(),
};
The state is an object. An attribute in the object is trying to call the result of a function. This might be the problem, as it would be asking an object to invoke functions. Try setting it to a fixed value first, and change the state value by invoking a mutation when needed.
You could also try js object function call to invoke the authenticate.isAuthenticated() function inside the state object.
Details here: https://www.w3schools.com/js/js_function_call.asp
Possible solution:
const state = {
authenticated: function(){ return authenticate.isAuthenticated() },
};
I do not think the problem is with using getters or state. Since state ran correctly, getters should do the same since it is pointing to state. Have you exported getters from your store? That seems to be the likely issue. As previously mentioned, you ought to pass state as a parameter when using vuex getters