Reputation: 341
My application is storing the entire state of a "board" in the board component vie useState
. I then map the state to create lists.
When I try to delete a list via an axios
call, and then splice that list from my state, I am encountering an issue. The target list is not being deleted, instead the last list of the board is being deleted instead. Here is a quick screen recording of the issue: https://streamable.com/uarb97
As you can see from the alerts, everything is going as expected. I don't see why the wrong list is being spliced. here is my handleDelete function that is being passed from the board component to each list component:
const handleDeleteList = (targetList) => {
event.preventDefault();
let newBoard = { ...boardState };
alert(`DELETING ${JSON.stringify(targetList.title)} FROM INDEX ${newBoard.lists.indexOf(targetList)}`)
newBoard.lists.splice(newBoard.lists.indexOf(targetList), 1);
alert(`BOARD WILL NOW HAVE LISTS: ${JSON.stringify(newBoard.lists)}`)
//setState function
setBoardState({ ...newBoard });
console.log("THIS IS THE CURRENT STATE THAT IS BEING MAPPED OVER TO DISPLAY THE LISTS")
console.log(boardState.lists)
};
EDIT: I have updated the handleDeleteList
function to use the setState function, but I am getting the same issue:
updateBoardState(oldBoard => {
const newBoard = { ...oldBoard }
newBoard.lists.splice(oldBoard.lists.indexOf(targetList), 1)
return newBoard
})
Is this a rendering issue, or am I missing something obvious?
Upvotes: 0
Views: 57
Reputation: 2152
The issue is:
updateBoardState(oldBoard => {
const newBoard = { ...oldBoard }
newBoard.lists.splice(oldBoard.lists.indexOf(targetList), 1)
return newBoard
})
When you spread oldBoard
you are making a shallow-copy of lists
which means this:
newBoard.lists.splice(oldBoard.lists.indexOf(targetList), 1)
Mutates oldBoard.lists
which causes React to get confused.
You can see this in a Code Sandbox which simulates this issue: https://codesandbox.io/s/sharp-bush-i4kew try and delete several items and you will see it getting more incorrect as it goes.
If you make a copy of lists
and do your splice on that, then construct your newBoard, you won't mutate oldBoard
:
updateBoardState(oldBoard => {
const lists = oldBoard.lists.slice();
lists.splice(oldBoard.lists.indexOf(targetList), 1);
return { ...oldBoard, lists };
});
Again, this is the same Code Sandbox with the working logic: https://codesandbox.io/s/confident-mcnulty-h7378
Upvotes: 1