I_A
I_A

Reputation: 341

react hooks update state issue

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

Answers (1)

user2340824
user2340824

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

Related Questions