I'm trying to initialize my Vuex store from Firestore. The last line of code context.commit('SET_ACTIVITIES', acts)
is what creates the error. I don't think I'm mutating the state directly since I'm using an action. What could I be missing?
Here's my Vuex store:
export default new Vuex.Store({
strict: true,
state: {
activities: []
},
mutations: {
SET_ACTIVITIES: (state, activities) => {
state.activities = activities
},
},
actions: {
fetchActivities: context => {
let acts = []
let ref = db.collection('activities')
ref.onSnapshot(snapshot => {
snapshot.docChanges().forEach(change => {
if(change.type == 'added') {
acts.push({
id: change.doc.id,
name: change.doc.data().name,
day: change.doc.data().day
})
}
})
})
context.commit('SET_ACTIVITIES', acts)
}
}
Also, it gives me the error equal to the number of items in Firestore. Why would it do that if I'm only doing one commit?
console:
[Vue warn]: Error in callback for watcher "function () { return this._data.$$state }": "Error: [vuex] do not mutate vuex store state outside mutation handlers."
and
Error: [vuex] do not mutate vuex store state outside mutation handlers.
at assert (vuex.esm.js?2f62:87)
at Vue.store._vm.$watch.deep (vuex.esm.js?2f62:763)
at Watcher.run (vue.runtime.esm.js?2b0e:4562)
at Watcher.update (vue.runtime.esm.js?2b0e:4536)
at Dep.notify (vue.runtime.esm.js?2b0e:730)
at Array.mutator (vue.runtime.esm.js?2b0e:882)
at eval (store.js?c0d6:36)
at eval (index.cjs.js?e89a:21411)
at eval (index.cjs.js?e89a:4904)
at LLRBNode.inorderTraversal (index.cjs.js?e89a:1899)
Error: [vuex] do not mutate vuex store state outside mutation handlers. The error means what it says. The solution is to mutate the store only with actions/mutations. You shallowly copy the array so it becomes a part of the store, then you continue to mutate it.
In strict mode, whenever Vuex state is mutated outside of mutation handlers, an error will be thrown. This ensures that all state mutations can be explicitly tracked by debugging tools.
In Vuex, mutations are synchronous transactions: store.
Mutations are intended to receive input only via their payload and to not produce side effects elsewhere. While actions get a full context to work with, mutations only have the state and the payload .
You're running into an issue with object references and asynchronous methods.
CollectionReference#onSnapshot()
is asynchronous, triggering the snapshot listener / observer on QuerySnapshot
events.
Basically what happens in your code is that you assign the empty array acts
to state.activities
(same object reference) in your mutation and then, at a later time in your snapshot event handler, directly push elements into it.
A quick solution would be to commit the mutation within the onSnapshot
observer
fetchActivities: context => {
let ref = db.collection('activities')
ref.onSnapshot(snapshot => {
let acts = []
snapshot.docChanges().forEach(change => {
if(change.type == 'added') {
acts.push({
id: change.doc.id,
name: change.doc.data().name,
day: change.doc.data().day
})
}
})
context.commit('SET_ACTIVITIES', acts)
})
}
If you only want to do an initial fetch of your collection data, use CollectionReference#get()
instead. Given it returns a promise, you can use this to make your action composable
async fetchActivities ({ commit }) {
let snapshot = await db.collection('activities').get()
let acts = snapshot.docChanges().filter(({ type }) => type === 'added')
.map(({ doc }) => ({
id: doc.id,
name: doc.data().name,
day: doc.data().day
}))
commit('SET_ACTIVITIES', acts)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With