3👍
The warning is caused by flatFilter()
, which mutates the input arr
inside the arr.filter()
callback, adding/updating a property:
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()
attempts to clone the original menuUser[]
from Vuex with:
filterItems(arr) {
const items = [...arr] // ❌ shallow copy
//...
}
…but the spread operator only creates a shallow copy, so the new array items still refer to the original items in menuUser[]
, leading to the mutation warning in flatFilter()
.
Solution
A quick fix is to deep copy the original array in filterItems
, using JSON.parse()
and JSON.stringify()
:
filterItems(arr) {
const items = JSON.parse(JSON.stringify(arr)) // ✅ deep copy
//...
}
Alternatively, flatFilter()
could be refactored to avoid the mutation (thus obviating the deep copy of the array in filterItems()
). flatFilter()
should do:
-
Filter the array by the comparison key. If the value of the object’s comparison key does not match the given value, allow it to pass the filter.
-
Map the resulting array to a new array. If the specified nested property exists, return a copy of the object that has the nested property updated recursively with the same filter (go to step
1
). -
Otherwise, return the original object (no change needed).
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
}
})
},
Now filterItems()
can pass the original input array to flatFilter()
without a deep copy:
filterItems(items) {
return this.flatFilter('items', 'visible', 0, items)
},
And the menuUser
-watcher and menuFiltered[]
data property could be replaced with this computed
property:
computedItems() {
return this.filterItems(this.menuUser)
},