【问题标题】:Why nuxt returning a mutate vuex store error为什么 nuxt 返回一个 mutate vuex 存储错误
【发布时间】:2021-11-18 01:46:08
【问题描述】:

我正在使用 Nuxt

我有一个简单的“Drawer.vue”组件。

在我的用户执行登录后,我尝试显示带有抽屉的页面。

如果登录成功,“auth”中间件会通过“/me”后端端点接收“菜单项”到抽屉。

我的问题是我收到下一个错误。 我已经看到这个问题Vuex - Do not mutate vuex store state outside mutation handlers,但是我没有在突变处理程序之外更改 vuex 存储状态。

//错误:

Error: [vuex] do not mutate vuex store state outside mutation handlers.
    at assert (vuex.esm.js?2f62:135)
    at Vue.store._vm.$watch.deep (vuex.esm.js?2f62:893)
    at invokeWithErrorHandling (vue.runtime.esm.js?2b0e:1863)
    at Watcher.run (vue.runtime.esm.js?2b0e:4584)
    at Watcher.update (vue.runtime.esm.js?2b0e:4558)
    at Dep.notify (vue.runtime.esm.js?2b0e:730)
    at Object.reactiveSetter [as items] (vue.runtime.esm.js?2b0e:1055)
    at eval (Drawer.vue?c84c:43)
    at Array.filter (<anonymous>)
    at VueComponent.flatFilter (Drawer.vue?c84c:40)

// Drawer.vue

<template>
  <div>
    {{ computedItems }}
  </div>
</template>

<script>
import { mapGetters } from 'vuex'
export default {
  name: 'DashboardCoreDrawer',

  data: () => ({
    menuFiltered: [],
    defaultMenu: [
      {
        icon: 'mdi-view-dashboard',
        title: 'Dashboard',
        to: '/',
        visible: 1,
      },
    ],
  }),

  computed: {
    ...mapGetters(['menuUser']),

    computedItems() {
      return this.menuFiltered
    },
  },

  watch: {
    menuUser(newValue) {
      this.menuFiltered = this.filterItems(newValue)
    },
  },

  methods: {
    flatFilter(nestedProp, compareKey, compareId, arr) {
      return arr.filter((o) => {
        const keep = o[compareKey] !== compareId
        if (keep && o[nestedProp]) {
          o[nestedProp] = this.flatFilter(
            nestedProp,
            compareKey,
            compareId,
            o[nestedProp]
          )
        }
        return keep
      })
    },
    filterItems(arr) {
      const items = [...arr]
      const res = this.flatFilter('items', 'visible', 0, items)
      return res
    },
  },
}
</script>

// index.js,在 Nuxt 存储文件夹中:

export const getters = {
  menuUser(state) {
    return state.auth.user?.menu || []
  },
}

【问题讨论】:

标签: javascript vue.js nuxt.js


【解决方案1】:

警告是由flatFilter() 引起的,它改变了arr.filter() 回调中的输入arr,添加/更新了一个属性:

flatFilter(nestedProp, compareKey, compareId, arr) {
  return arr.filter((o) => {
    const keep = o[compareKey] !== compareId
    if (keep && o[nestedProp]) {
      o[nestedProp] = this.flatFilter(/*...*/)
      ^^^^^^^^^^^^^^^
    }
    return keep
  })
},

filterItems() 尝试从 Vuex 克隆原始的 menuUser[]

filterItems(arr) {
  const items = [...arr] // ❌ shallow copy
  //...
}

...但是扩展运算符只创建了一个shallow copy,所以新的数组项仍然引用menuUser[]中的原始项,导致flatFilter()中的突变警告。

解决方案

快速解决方法是深拷贝filterItems 中的原始数组,使用JSON.parse()JSON.stringify()

filterItems(arr) {
  const items = JSON.parse(JSON.stringify(arr)) // ✅ deep copy
  //...
}

demo 1

或者,flatFilter() 可以重构以避免突变(从而避免filterItems() 中数组的深层副本)。 flatFilter() 应该这样做:

  1. 通过比较键过滤数组。如果对象的比较键的值与给定的值不匹配,则允许它通过过滤器。

  2. 将结果数组映射到新数组。如果指定的嵌套属性存在,则返回嵌套属性使用相同过滤器递归更新的对象的副本(转到步骤1)。

  3. 否则,返回原始对象(无需更改)。

flatFilter(nestedProp, compareKey, compareId, arr) {
  return arr
    // 1️⃣
    .filter((o) => o[compareKey] !== compareId)

    .map((o) => {

      // 2️⃣
      if (o[nestedProp]) {
        return {
          ...o,
          [nestedProp]: this.flatFilter(nestedProp, compareKey, compareId, o[nestedProp]),
        }

      // 3️⃣
      } else {
        return o
      }
    })
},

现在filterItems() 可以将原始输入数组传递给flatFilter() 而无需深拷贝:

filterItems(items) {
  return this.flatFilter('items', 'visible', 0, items)
},

并且menuUser-watcher 和menuFiltered[] 数据属性可以替换为computed 属性:

computedItems() {
  return this.filterItems(this.menuUser)
},

demo 2

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-09-10
    • 2019-05-26
    • 2019-06-20
    • 1970-01-01
    • 2012-04-10
    • 1970-01-01
    • 2018-05-22
    • 2019-09-23
    相关资源
    最近更新 更多