fix: vuex mutation violation from draggable #674
No reviewers
Labels
No Label
area/internal-code
changes requested
confirmed
dependencies
duplicate
good first issue
help wanted
hosting
invalid
kind/bug
kind/feature
question
wontfix
No Milestone
No project
No Assignees
2 Participants
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: vikunja/frontend#674
Loading…
Reference in New Issue
No description provided.
Delete Branch "dpschen/frontend:feature/fix-mutation-violation"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The order of the list was originally updated by a sideeffect of the v-model.
Since the data is mapped from the store this created a vuex mutation violation (data was edited by the v-model instead of a vuex mutation).
In order to fix this I did the following:
create a computed for the filteredList -> No need to combine v-for and v-if for the list items
use value and @input instead of v-model for the draggable
create a new updateFilteredLists method that replaces the namespace with the old list with a one that includes a fresh list with the new order.
the list service returned the same model again. I got there some mutation problems aswell, so I return now a new model.
vuex lists module
vuex namespaces module
The old setNamespaceById used "for ... in" to iterate and get the list index. this is wrong! See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in#array_iteration_and_for...in
Quote: "Note: for...in should not be used to iterate over an Array where the index order is important."
instead I find the index now with
Array.findIndex
.I also removed the line
namespace.lists = state.namespaces[n].lists
The reason was that the new namespace included the new ordered lists, so by overwriting it with the old one the modification wouldn't be saved.
I hope this doesn't leave to errors somewhere else.
@ -81,2 +81,3 @@
<draggable
v-model="n.lists"
:value="filteredLists[nk]"
@input="(lists) => updateFilteredLists(n, lists)"
Could you achieve the same effect with a setter for the computed property?
In theory yes. But in order to do so it would need to know the current namespace.
The name was inspired by your
listsFiltered
in thesaveListPosition
function.Does not work :/
I see, makes sense then. Could you add a comment about this then so that future readers of the code know why there isn't a setter?
@ -177,0 +174,4 @@
menuActive: MENU_ACTIVE,
loading: state => state[LOADING] && state[LOADING_MODULE] === 'namespaces',
}),
filteredLists() {
Maybe this should be called something like
namespacesWithFilteredLists
(I know, long) to make it clear this is not just an array of lists but an array of namespaces with filtered lists?But the computed is just an array of the lists. No namespaces.
How about
activeLists
In the sense of
!archived === active
My bad, I thought it was everything.
I think that would work great.
@ -25,2 +25,4 @@
export const store = new Vuex.Store({
// TODO: enable this to catch all vuex mutation violations
// strict: import.meta.env.DEV,
Please remove the
TODO
and either just uncomment it so it is always enabled when in dev mode or remove it entirely.I wonder how the changes affect the performance of it - replacing whole models is probably i bit more expensive in terms of cpu ressouces, but probably not noticable.
Thanks for pointing that out, I did not know that.
This shouldn't be a problem. Replacing large chunks is a common thing to do!
Most of the time it's more important, because we let the browser / vue / vuex do it's magic instead of trying to build update code that is as performant.
Vue won't replace the whole object. Instead it will diff the difference.
I guess this is fine then. Thanks for the explanation.
I think it should now all be resolved :)
864f5ced76
to8e32d23bff