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>
Related
I'm having trouble understanding how to interact with my local state from my vuex state. I have an array with multiple items inside of it that is stored in vuex state. I'm trying to get that data from my vuex state into my components local state. I have no problems fetching the data with a getter and computed property but I cannot get the same data from the computed property into local state to manipulate it. My end goal is to build pagination on this component.
I can get the data using a getters and computed properties. I feel like I should be using a lifecycle hook somewhere.
Retrieving Data
App.vue:
I'm attempting to pull the data before any components load. This seems to have no effect versus having a created lifecycle hook on the component itself.
export default {
name: "App",
components: {},
data() {
return {
//
};
},
mounted() {
this.$store.dispatch("retrieveSnippets");
}
};
State:
This is a module store/modules/snippets.js
const state = {
snippets: []
}
const mutations = {
SET_SNIPPETS(state, payload) {
state.snippets = payload;
},
}
const actions = {
retrieveSnippets(context) {
const userId = firebase.auth().currentUser.uid;
db.collection("projects")
.where("person", "==", userId)
.orderBy("title", "desc")
.onSnapshot(snap => {
let tempSnippets = [];
snap.forEach(doc => {
tempSnippets.push({
id: doc.id,
title: doc.data().title,
description: doc.data().description,
code: doc.data().code,
person: doc.data().person
});
});
context.commit("SET_SNIPPETS", tempSnippets);
});
}
}
const getters = {
getCurrentSnippet(state) {
return state.snippet;
},
Inside Component
data() {
return {
visibleSnippets: [],
}
}
computed: {
stateSnippets() {
return this.$store.getters.allSnippets;
}
}
HTML:
you can see that i'm looping through the array that is returned by stateSnippets in my html because the computed property is bound. If i remove this and try to loop through my local state, the computed property doesn't work anymore.
<v-flex xs4 md4 lg4>
<v-card v-for="snippet in stateSnippets" :key="snippet.id">
<v-card-title v-on:click="snippetDetail(snippet)">{{ snippet.title }}</v-card-title>
</v-card>
</v-flex>
My goal would be to get the array that is returned from stateSnippets into the local data property of visibleSnippets. This would allow me to build pagination and manipulate this potentially very long array into something shorter.
You can get the state into your template in many ways, and all will be reactive.
Directly In Template
<div>{{$store.state.myValue}}</div>
<div v-html='$store.state.myValue'></div>
Using computed
<div>{{myValue}}</div>
computed: {
myValue() { return this.$store.state.myValue }
}
Using the Vuex mapState helper
<div>{{myValue}}</div>
computed: {
...mapState(['myValue'])
}
You can also use getters instead of accessing the state directly.
The de-facto approach is to use mapGetters and mapState, and then access the Vuex data using the local component.
Using Composition API
<div>{{myValue}}</div>
setup() {
// You can also get state directly instead of relying on instance.
const currentInstance = getCurrentInstance()
const myValue = computed(()=>{
// Access state directly or use getter
return currentInstance.proxy.$store.state.myValue
})
// If not using Vue3 <script setup>
return {
myValue
}
}
I guess you are getting how Flux/Vuex works completely wrong. Flux and its implementation in Vuex is one way flow. So your component gets data from store via mapState or mapGetters. This is one way so then you dispatch actions form within the component that in the end commit. Commits are the only way of modifying the store state. After store state has changed, your component will immediately react to its changes with latest data in the state.
Note: if you only want the first 5 elements you just need to slice the data from the store. You can do it in 2 different ways:
1 - Create a getter.
getters: {
firstFiveSnipets: state => {
return state.snipets.slice(0, 5);
}
}
2 - Create a computed property from the mapState.
computed: {
...mapState(['allSnipets']),
firstFiveSnipets() {
return this.allSnipets.slice(0, 5);
}
}
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 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() {
}
}
}
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.
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