How can I send parameter with getters in nuxt? - vue.js

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

Nuxt store getter not working, ID given to payload is not an Integer + Error: [vuex] do not mutate vuex store state outside mutation handlers

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.

How to update state data that is dependant on another state async data

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 have a problem using rootGetters in Nuxt.js

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"]);
}

Vuex getters with params

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.

Can I dispatch vuex action inside getter function?

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.