Reputation: 2048
I'm trying to create a listenAuth function that watches "onAuthStateChanged" in firebase to notify the vuex store when a user has logged in or out. As far as I can tell, I'm only modifying state.authData using the mutation handler, unless I'm missing something?
I'm getting the error:
[vuex] Do not mutate vuex store state outside mutation handlers.
Here's my App.vue javascript (from my component)
<script>
// import Navigation from './components/Navigation'
import * as actions from './vuex/actions'
import store from './vuex/store'
import firebase from 'firebase/app'
export default {
store,
ready: function () {
this.listenAuth()
},
vuex: {
actions,
getters: {
authData: state => state.authData,
user: state => state.user
}
},
components: {
// Navigation
},
watch: {
authData (val) {
if (!val) {
this.redirectLogin
this.$route.router.go('/login')
}
}
},
methods: {
listenAuth: function () {
firebase.auth().onAuthStateChanged((authData) => {
this.changeAuth(authData)
})
}
}
}
</script>
Here's my action (changeAuth) function
export const changeAuth = ({ dispatch, state }, authData) => {
dispatch(types.AUTH_CHANGED, authData)
}
Here's my store (the parts that matter)
const mutations = {
AUTH_CHANGED (state, authData) {
state.authData = authData
}
}
const state = {
authData: {}
}
Upvotes: 10
Views: 17620
Reputation: 9050
So from many answers we can agree on the cause: the object stored in the state is silently modified by something that holds reference to it. And many suggest making a copy of the object.
The other alternative is to empty the state while the object is being modified. This works when for some reason you cannot copy the object. For example:
bla({ state } {}) {
mutatingMethod(state.xxx);
},
If you know mutatingMethod
is modifying xxx then you can do something like this:
bla({ state } {}) {
let xxx = state.xxx
commit("SET_XXX", null)
mutatingMethod(xxx);
commit("SET_XXX", xxx)
},
Upvotes: 0
Reputation: 4350
For anybody who's also struggling with this, this is another way to fix it (what actually worked for me):
auth()
.onAuthStateChanged((user) => {
if (user) {
commit(MUTATION_TYPES.SET_USER, { ...user.toJSON() });
}
})
Upvotes: -1
Reputation: 19
I had this issue too, and I used lodash to clone data
state.someStatehere = $lodash.cloneDeep(data)
Upvotes: 0
Reputation: 1313
I also came across this issue. My store:
state: {
items: []
},
mutations: {
SetItems (state, payload) {
// Warning
state.items = payload.items
}
},
actions: {
FetchItems ({commit, state}, payload) {
api.getItemsData(payload.sheetID)
.then(items => commit('SetItems', {items}))
}
}
Fixed it by replace state.items = payload.items
with:
state.items = payload.items.slice()
The reason is that arrays are stored as references in Javascript and
payload.items
is likely to be changed outside Vuex. So we should just use a fresh copy ofpayload.items
instead.
For state objects, use:
state.someObj = Object.assign({}, payload.someObj)
And don't use JSON.parse(JSON.stringify(someObj))
as it's much slower.
Upvotes: 19
Reputation: 931
After struggling with the same problem, I found that the error only happens when we try to store the auth/user data in the Vuex state.
Changing from...
const mutations = {
AUTH_CHANGED (state, authData) {
state.authData = authData
}
}
...to...
const mutations = {
AUTH_CHANGED (state, authData) {
state.authData = JSON.parse(JSON.stringify(authData))
}
}
would solve your case.
Upvotes: 11