I want send id with $route.params.id in getters but it does not work!
In my component I have blogs object; I want save this.$route.params.id in blogId and then pass it with my getters method like this:
created() {
const blogId = this.$route.params.id;
console.log(blogId); ////1
this.blog=this.$store.getters.getBlogById(blogId);
console.log(this.blog);
},
but
console.log(this.blog) is undefined
when I send a number like this:
$store.getters.getBlogById(2)
it works and console.log(this.blog) print my object
What should I do?
my getters:
const getters = {
allBlogs: state => state.blogs,
getBlogById: (state) => (id) => {
return state.blogs.find(blog => blog.id == id)
}
}
const blogId = this.$route.params.id - is a string, and in getter your are using ===, I think that's the reason.
Related
I am trying to make a product detail page. The detail page is named _id.
When opened the id is replaced with the product id. On opening the page the state is set with data fetched from an api.
After that i am trying to use a computed property that refers to a getter named getProduct() with an id (this.$route.params.id) in the payload.
This is how my _id.vue looks like:
methods: {
...mapActions("products", ["fetchProducts",]),
...mapGetters("products", ["getProduct",]),
},
async mounted() {
this.fetchProducts()
},
computed: {
product() {
return this.getProduct(this.$route.params.id)
}
}
This is how my store file named products.js looks like:
import axios from "axios"
export const state = () => ({
producten: []
})
export const mutations = {
setProducts(state, data) {
state.producten = data
}
}
export const getters = {
getProduct(state, id) {
console.log(id)
return state.producten.filter(product => product.id = id)
}
}
export const actions = {
async fetchProducts({ commit }) {
await axios.get('/api/products')
.then(res => {
var data = res.data
commit('setProducts', data)
})
.catch(err => console.log(err));
}
}
What works is creating the state, but when i try to use the getter something goes wrong.
As you can see i console.log() the id given to it. Which logs the following:
I also get the error: client.js?06a0:103 Error: [vuex] do not mutate vuex store state outside mutation handlers.
Which I'm not doing as far as I know?
**Note: **these errors get logged as much as the length of my state array is.
From the Vuex documentation:
Vuex allows us to define "getters" in the store. You can think of them as computed properties for stores. Like computed properties, a getter's result is cached based on its dependencies, and will only re-evaluate when some of its dependencies have changed.
Like computed, getters does not support having arguments.
But there is a way to have "method-style access" to a getter: https://vuex.vuejs.org/guide/getters.html#property-style-access
You can also pass arguments to getters by returning a function. This is particularly useful when you want to query an array in the store:
getters: {
// ...
getTodoById: (state) => (id) => {
return state.todos.find(todo => todo.id === id)
}
}
store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }
Note that getters accessed via methods will run each time you call them, and the result is not cached.
In a Nuxt application I have a Vuex store that first gets some "properties" via fetch from an external URL. I would like to then use this data to update another
state element called "locations", each of these "properties" have a "location" but I'm not sure how to run this only after all of the properties have been fetched.
export const mutations = {
updateProperties: (state, properties) => {
state.properties = properties
},
updateLocations: (state) => {
const locationsArr = [...new Set( state.properties.map( property => property.acf.location_tab_group.location_table.city ) )]
state.locations = locationsArr;
}
}
export const actions = {
async getProperties({ state, commit }) {
if (state.properties.length) return
try {
let properties = await fetch(
`https://...`
).then((res) => res.json())
properties = properties
.filter((el) => el.status === 'publish')
.map(({ id, slug, title, acf }) => ({
id,
slug,
title,
acf,
}))
commit('updateProperties', properties)
} catch (err) {
console.log(err)
}
},
getLocations({state, commit}) {
if(state.properties.length) {
const locationsArr = [...new Set( state.properties.map( property => property.acf.location_tab_group.location_table.city ) )]
commit('updateLocations', locationsArr)
}
}
}
So basically, I'd like to know how to call the "updateLocations" mutation only after all of the properties have been fetched.
In any action, dispatch is available on the context object.
If I understand you right, you want to make sure getProperties has been called at least once before calling getLocations?
Is this what you were thinking about?
async getLocations({state, commit, dispatch}) {
if(!state.properties.length) {
await dispatch('getLocations');
}
const locationsArr = [...new Set( state.properties.map( property => property.acf.location_tab_group.location_table.city ) )]
commit('updateLocations', locationsArr);
}
I think it's a problem with rootGetters or data types.
// sheet.js
// character = Object
// number = 100
export const getters = {
getNumber: state => {
return Number(state.character.number); // its return 100
}
};
and called getNumber to preview.js.
// preview.js
export const state = () => ({
dummy: 0
});
export const getters = {
numberIs: (state, rootGetters) => {
return Math.round(state.dummy + rootGetters["sheet/getNumber"]); // undefined
}
};
and numberIs return undefined.
What did I miss?
The order of the parameters matters. Vuex getter signature is (state, getters, rootState, rootGetters), so currently what you think is rootGetters is actually just getters.
https://vuex.vuejs.org/guide/modules.html#accessing-global-assets-in-namespaced-modules
It's a little bit deceptive because of how actions pass in the context-object, where you can pick and choose what you want to use. Here you must use 4 parameters to get to rootGetters. (Or parse it out from arguments)
numberIs: (state, _whatever, _idontcare, rootGetters) => {
return Math.round(state.dummy + rootGetters["sheet/getNumber"]);
}
I am wondering why can't I use vuex getter with property with default value like this:
getters: {
getTest: (state, property = 'current') => {
return state.test[property]
}
}
and when I use it like this getTest.includes('something') it doesn't work but if I use it like this getTest().includes('something') it works?
Since when there are no params used it works without ()
https://vuex.vuejs.org/guide/getters.html#method-style-access
getters: {
getTest: (state) => (property = 'current') => {
return state.test[property]
}
}
// example usage
this.getTest().includes('something')
The second argument of the getters is the other getters :
Getters will also receive other getters as the 2nd argument
(https://vuex.vuejs.org/guide/getters.html#property-style-access)
So your property parameter will be an array, thus state.test[property] always returns undefined
To use a getter as a function with parameters, you need to make your getter return a function, as shown here: https://vuex.vuejs.org/guide/getters.html#method-style-access
getters: {
getCarteiraPeloId: (state) => (id) => {
return state.carteiras.find(thing => thing.id === id) || { nome: 'Não Encontrado' }
}
That is it.
I want to dispatch action inside getter function.
1. Is it possible and right.
2. If yes how can I do it?
I guess it will be something like this dispatch('GET_BOOKS');
const getters = {
getAllBooksDispatch: (state, getters, dispatch) => {
if (state.books === null) {
dispatch('GET_BOOKS');
}
return state.books
},
};
But it does not work.
So my store file looks like this.
const initialState = {
books: null
};
const getters = {
getAllBooksDispatch: (state, getters, dispatch) => {
if (state.books === null) {
dispatch('GET_BOOKS');
}
return state.books
},
};
const mutations = {
SET_BOOKS: (state,{data}) => {
console.log('SET_BOOKS mutations')
state.books = data;
},
};
const actions = {
GET_BOOKS: async ({ commit }) => {
let token = users.getters.getToken;
let query = new Promise((resolve, reject) => {
axios.get(config.api + 'books', {token}).then(({data}) => {
if (data) {
commit('SET_BOOKS', {data: data})
resolve()
} else {
reject(data.message);
}
}).catch(() => {
reject('Error sending request to server!');
})
})
},
};
No, you can't. At least not the way you want to. The third argument in a getter is the rootState object when using modules, not dispatch. Even if you find a way to dispatch an action inside a getter it won't work the way you expect. Getters must be synchronous, but actions can be (and in this example are) asynchronous. In your example, GET_BOOKS would be dispatched but the getter would still return state.books as null.
I'd recommend handling this sort of lazy-loading outside of the Vuex store.