Fix bug caused by inconsistent Todo state across components in the Basic chapter of the Docs #795
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
The tutorial for the TodoMVC app in documentation, the visibleTodos prop is passed to TodoList, which is mapped into a new array -- which I will call visibleTodos -- and rendered into Todo components. Upon doing so, the visibleTodos array now is at risk of becoming unlinked with the state.todos array as soon as a single item is completed.
Because the completeTodo reducer relies on parity between the indexes of the visibleTodos array and the state.todos array, bugs can occur when in trying to dispatch a completeTodo action in SHOW_ACTIVE view mode. The bug occurs because the visibleTodos array can be shorter than the state.todos array, and any index in the list can be filtered out once completed.
In the screen shot below, "third" has already been completed. When clicking on "fourth" todo -- the fourth item in the state.todos array and third item in the visibleTodos array, the payload informs the app that it should complete the third item in the array, so nothing happens.
Likewise, when clicking on the "fifth" todo --- fifth in state.todos but fourth in visibleTodos, it completes the "fourth" item by dispatching a payload targeting the index: 3.
I have crafted two solutions. The first is to map a uuid to each todo and have the completeTodo action splice the array using the index returned by Array.prototype.findIndex(todo.id) instead of the current position of the Todo in the visibleTodos array. This solution fixes the inaccuracies of the reducer, but it also requires actions and the reducer to be rewritten and another module to be installed. I'm not a fan.
Instead, why not pass the filtering mechanisms themselves to TodoList component via props by altering the selectTodos helper to return functions instead of filtered arrays? Now we are free to pass the entire state.todos array to TodoList and simply not render any todo within it that doesn't return true when passed to the filtering function. This keeps our state consistent across components without altering any reducers or actions. I believe this to be the elegant solution. It is included in this PR.
My apologies for such a big switch.