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 存储状态

Vuex 和 VueJS(不要在突变处理程序之外改变 vuex 存储状态)

错误:[vuex] 不要在突变处理程序之外改变 vuex 存储状态。 NUXT