Vuex - '不要在突变处理程序之外改变 vuex 存储状态'
Posted
技术标签:
【中文标题】Vuex - \'不要在突变处理程序之外改变 vuex 存储状态\'【英文标题】:Vuex - 'do not mutate vuex store state outside mutation handlers'Vuex - '不要在突变处理程序之外改变 vuex 存储状态' 【发布时间】:2019-09-24 13:37:08 【问题描述】:我正在尝试从 Firestore 初始化我的 Vuex 存储。最后一行代码context.commit('SET_ACTIVITIES', acts)
是造成错误的原因。我不认为我正在直接改变状态,因为我正在使用一个动作。我可能会错过什么?
这是我的 Vuex 商店:
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)
此外,它给我的错误等于 Firestore 中的项目数。如果我只进行一次提交,它为什么会这样做?
控制台:
[Vue 警告]:观察者“function () return this._data.$$state ”的回调出错:“错误:[vuex] 不要在突变处理程序之外改变 vuex 存储状态。”
和
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)
【问题讨论】:
你真的要使用onSnapshot()
吗?每次您的数据更改时都会触发。我只问你只是在onSnapshot
观察者之外提交突变,这让我认为你只想这样做一次
@Phil 阅读下面的回复后,您在这里所说的完全有道理。为了清楚起见,如果我创建数组并在onSnapshot
内提交,那么一切都会按顺序发生。以我的方式,onSnapshot
在提交之前没有完成?
所以基本上我在状态更新后引用了acts
数组,所以我实际上是在直接改变状态,因为行为仍然与状态相关联?
就是这样。 onSnapshot
观察者会在您的集合每次更改时继续执行,因此它不仅会在您提交后运行,还会继续这样做。
【参考方案1】:
您遇到了对象引用和异步方法的问题。
CollectionReference#onSnapshot()
是异步的,在QuerySnapshot
事件上触发快照侦听器/观察器。
基本上,您的代码中发生的情况是,您在突变中将空数组 acts
分配给 state.activities
(相同的对象引用),然后稍后在您的 snapshot 事件处理程序中,直接将元素推入其中。
一个快速的解决方案是在 onSnapshot
观察者内提交突变
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)
)
如果您只想对集合数据进行初始提取,请改用CollectionReference#get()
。鉴于它返回一个承诺,您可以使用它来执行您的操作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)
【讨论】:
非常感谢菲尔。我很感激你的时间。 :) 我有完全相同的问题,但你给出的第一个解决方案是我已经有的,它仍然给我突变错误。知道为什么吗? 我在更改作为道具传递给 Vue 中的子组件的对象或数组时遇到了类似的问题。一般来说,当你想丢失一个数组的引用时,你可以_.clone()
它或在它包含对象时使用_.cloneDeep()
(带lodash)。
'doh,你为我节省了更多个小时的困惑。谢谢!以上是关于Vuex - '不要在突变处理程序之外改变 vuex 存储状态'的主要内容,如果未能解决你的问题,请参考以下文章
Vuex - '不要在突变处理程序之外改变 vuex 存储状态'
Vuex 突变引发错误 - 不要在突变处理程序之外改变 vuex 存储状态
nuxt vuex:不要在突变处理程序之外改变 vuex 存储状态
错误:[vuex] 不要在突变处理程序之外改变 vuex 存储状态