Vuex 和 VueJS(不要在突变处理程序之外改变 vuex 存储状态)
Posted
技术标签:
【中文标题】Vuex 和 VueJS(不要在突变处理程序之外改变 vuex 存储状态)【英文标题】:Vuex & VueJS (Do not mutate vuex store state outside mutation handlers) 【发布时间】:2016-11-16 19:58:10 【问题描述】:我正在尝试创建一个 listenAuth 函数来监视 firebase 中的“onAuthStateChanged”以通知 vuex 商店 当用户登录或退出时。据我所知,我只是在使用突变处理程序修改 state.authData,除非我遗漏了什么?
我收到错误消息:
[vuex] Do not mutate vuex store state outside mutation handlers.
这是我的 App.vue javascript(来自我的组件)
<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>
这是我的操作(changeAuth)函数
export const changeAuth = ( dispatch, state , authData) =>
dispatch(types.AUTH_CHANGED, authData)
这是我的商店(重要的部分)
const mutations =
AUTH_CHANGED (state, authData)
state.authData = authData
const state =
authData:
【问题讨论】:
你可能想升级到 Vuex 2.0 【参考方案1】:我也遇到过这个问题。我的商店:
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))
将state.items = payload.items
替换为:
state.items = payload.items.slice()
原因是数组作为引用存储在 javascript 中,
payload.items
很可能在 Vuex 之外被更改。所以我们应该 只需使用payload.items
的新副本即可。
对于状态对象,使用:
state.someObj = Object.assign(, payload.someObj)
并且不要使用JSON.parse(JSON.stringify(someObj))
,因为它要慢得多。
【讨论】:
【参考方案2】:在解决了同样的问题后,我发现只有当我们尝试将 auth/user 数据存储在 Vuex 状态时才会发生错误。
改变...
const mutations =
AUTH_CHANGED (state, authData)
state.authData = authData
...到...
const mutations =
AUTH_CHANGED (state, authData)
state.authData = JSON.parse(JSON.stringify(authData))
会解决你的问题。
【讨论】:
请改用state.authData = Object.assign(, authData)
。看看我下面的答案。
由于某种原因 Object.assign(, authData)
不起作用,但 JSON.parse(JSON.stringify(authData))
起作用。
Object.assign
有时不起作用的原因是因为它不执行深层复制,如文档 "For deep cloning, we need to use other alternatives because Object.assign() copies property values. If the source value is a reference to an object, it only copies that reference value."
中所述。对于深度克隆,JSON.parse(JSON.stringify(obj))
更好,即使它肯定会更慢
赞成建议的替代方案,也适用于我的身份验证
我想问为什么这个解决方案有效,因为没有解释。【参考方案3】:
我也有这个问题,我用lodash克隆数据
state.someStatehere = $lodash.cloneDeep(data)
【讨论】:
【参考方案4】:所以从许多答案中我们可以就原因达成一致:存储在状态中的对象被持有对它的引用的东西默默地修改。许多人建议制作对象的副本。
另一种选择是在修改对象时清空状态。当由于某种原因您无法复制对象时,此方法有效。 例如:
bla( state )
mutatingMethod(state.xxx);
,
如果您知道mutatingMethod
正在修改 xxx,那么您可以这样做:
bla( state )
let xxx = state.xxx
commit("SET_XXX", null)
mutatingMethod(xxx);
commit("SET_XXX", xxx)
,
【讨论】:
【参考方案5】:对于同样为此苦苦挣扎的任何人,这是解决它的另一种方法(实际上对我有用):
auth()
.onAuthStateChanged((user) =>
if (user)
commit(MUTATION_TYPES.SET_USER, ...user.toJSON() );
)
【讨论】:
以上是关于Vuex 和 VueJS(不要在突变处理程序之外改变 vuex 存储状态)的主要内容,如果未能解决你的问题,请参考以下文章
Vuex 突变引发错误 - 不要在突变处理程序之外改变 vuex 存储状态
nuxt vuex:不要在突变处理程序之外改变 vuex 存储状态
错误:[vuex] 不要在突变处理程序之外改变 vuex 存储状态。 NUXT
错误:[vuex] 不要在突变处理程序之外改变 vuex 存储状态