estoy usando nuxt
Tengo un componente simple 'Drawer.vue'.
Después de que mi usuario ejecute un inicio de sesión, intento mostrar la página con el cajón.
Si el inicio de sesión fue exitoso, el midleware 'auth' recibe los 'elementos de menú' en el cajón por el punto final de back-end '/me'.
Mi problema es que estoy recibiendo el siguiente error. He visto esta pregunta Vuex: no mute el estado de la tienda vuex fuera de los controladores de mutación , pero AFAIK no estoy cambiando el estado de la tienda vuex fuera de los controladores de mutación.
//Error:
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)// Cajón.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, en la carpeta de la tienda Nuxt:
export const getters = { menuUser(state) { return state.auth.user?.menu || [] }, }La advertencia es causada por flatFilter() , que muta el arr de entrada dentro de la devolución de llamada arr.filter() , agregando/actualizando una propiedad:
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() intenta clonar el menuUser[] original de Vuex con:
filterItems(arr) { const items = [...arr] // ❌ shallow copy //... } ...pero el operador de propagación solo crea una copia superficial , por lo que los nuevos elementos de la matriz aún se refieren a los elementos originales en menuUser[] , lo que lleva a la advertencia de mutación en flatFilter() .
Una solución rápida es copiar en profundidad la matriz original en filterItems , usando JSON.parse() y JSON.stringify() :
filterItems(arr) { const items = JSON.parse(JSON.stringify(arr)) // ✅ deep copy //... } Alternativamente, flatFilter() podría refactorizarse para evitar la mutación (obviando así la copia profunda de la matriz en filterItems() ). flatFilter() debería hacer:
Filtre la matriz por la clave de comparación. Si el valor de la clave de comparación del objeto no coincide con el valor dado, permita que pase el filtro.
Asigne la matriz resultante a una nueva matriz. Si existe la propiedad anidada especificada, devuelva una copia del objeto que tiene la propiedad anidada actualizada recursivamente con el mismo filtro (vaya al paso 1 ).
De lo contrario, devuelva el objeto original (no se necesita cambio).
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 } }) }, Ahora filterItems() puede pasar la matriz de entrada original a flatFilter() sin una copia profunda:
filterItems(items) { return this.flatFilter('items', 'visible', 0, items) }, Y la propiedad de datos menuUser -watcher y menuFiltered[] podría reemplazarse con esta propiedad computed :
computedItems() { return this.filterItems(this.menuUser) },