I'm having real difficulties with combining onSnapshot with getDownloadURL in my actions and setting it on mutations to change my state in vuex. I keep getting "[vuex] do not mutate vuex store state outside mutation handlers" error.
Here is a sample of my code:
state = () => ({
products:[]
})
mutations = {
setProducts(state, products) {
state.products = products
console.log(state.products)
},
}
actions = {
setProducts({commit}) {
let colRef = collection(db, 'products')
const unsub = onSnapshot(colRef, snapshot => {
let products = []
snapshot.docs.forEach(doc => {
const imageDownloadURL = getDownloadURL(ref(storage, `${doc.data().imageRef}`))
.then( url => {
// console.log(url)
products.push({
id: doc.id,
name: doc.data().name,
price: doc.data().price,
description: doc.data().description,
imageURL: url
})
commit('setProducts', products)
})
})
})
},
}
I've got a collection that looks like the following:
{
id: 1,
name: 'NotPot Orange',
price: '8.80',
description: 'This is an orange flavour vitamin',
imageURL: 'images/notpot1.jpg'
},
My console.log gives the data I want in this output:
{
id: 'qv1t4f2NfAo9N4YrkXzg',
name: 'NotPot Citrus',
price: '6.50',
description: 'This is a citrus flavour vitamin',
imageURL: 'https://firebasestorage.googleapis.com/v0/b/blahblahblah-
project.appspot.com/o/images%2Fnotpot5.jpg?alt=media&token=385a5a25-ef2c'
},
I've got a getter which I grab in my v-for:
getters = {
products: (state) => {
return state.products
},
}
like so:
<feature-product
v-for="product in this.$store.getters.products"
:key="product.id"
:product="product"
/>
Am I missing smth? I'm really not so versed with onSnapshot and getDownloadURL - so I feel like it's a mistake somewhere there. I heard smth about needing to deepClone/deepCopy but not sure what that means. Any clue or point to the right direction will help out loads! Thanks in advance!
I'm still not 100% sure if this is the correct method - but I got it to work with {getDocs} from 'firebase/firestore' along side {ref, getDownloadURL} from 'firebase/storage'
I decided to drop the aforementioned real-time data pull to just getDocs in one go - so its not exactly how I wanted it but I thought it's still applicable to my use case. Here's my changes:
actions = {
async setProducts({commit}) {
let colRef = collection(db, 'products')
const querySnapshot = await getDocs(colRef)
querySnapshot.forEach((doc) => {
let products
const imageDownloadURL = getDownloadURL(ref(storage, `${doc.data().imageRef}`))
.then( url => {
// console.log(url)
products = ({
id: doc.id,
name: doc.data().name,
price: doc.data().price,
description: doc.data().description,
imageURL: url
})
commit('setProducts', products)
})
})
}
}
changes to my mutations:
mutations = {
setProducts(state, products) {
state.products.push(products)
console.log(state.products)
},
}
P.S. to get it to be load at the earliest possible point - you can use beforeCreated() or created() lifecycle hooks to dispatch the 'setProducts' action.
Hope this helps for anyone else stuck on smth similar.