2

I'm updating an object within react's state which I use to display a list. The state updates correctly, however the display breaks.

This is the section of the code from inside my render function which produces the list.

this.state.shoppingItems ? this.state.shoppingItems.currentShoppingItems.map((item, index) => {
    console.log(item)
    return <ItemSummary key={index} onClickHandler={this.selectItem} updateShoppingItem={this.updateCurrentShoppingItem} shoppingItem={item} removeFromCurrentItems={this.removeFromCurrentItems} addToCurrentList={this.addToCurrentList} />
}) : undefined} 

Here is the code that produces the previous items list:

this.state.shoppingItems ? this.state.shoppingItems.previousShoppingItems.map((item, index) => {
    console.log(item)
    return <ItemSummary key={index} onClickHandler={this.selectItem} updateShoppingItem={this.updateCurrentShoppingItem} shoppingItem={item} removeFromCurrentItems={this.removeFromCurrentItems} addToCurrentList={this.addToCurrentList} />
}) : undefined} 

This is the method which removes the item from the current list and adds it to the previous list, where the issue occurs.

removeFromCurrentItems(shoppingItem) {
        const items = this.state.shoppingItems.currentShoppingItems.filter(item => item._id !== shoppingItem._id);
        let shoppingItems = this.state.shoppingItems;
        shoppingItems.currentShoppingItems = items;
        shoppingItem.number = 0;
        shoppingItem.completed = false;
        shoppingItems.previousShoppingItems.push(shoppingItem);
        this.setState({
            shoppingItems: shoppingItems
        });
        // call to API to update in database
    }

Here is the list before I remove the item. List of shopping Items

Here is the list after I remove the middle item:

List of shopping items with 1 removed

Finally here is the console.log output which shows that the items have updated properly but the display hasn't updated:

Console log output showing shopping items

I'm entirely new to react coming from angular so I have no idea if this is the correct way to do this or if there is a better way. But could somebody help me figure out why the display isn't updating?

sunalive
  • 255
  • 4
  • 13

3 Answers3

3

The issue seemed to be the key on the item in the map. I replaced the index with the item's id from the database as below and now it renders properly.

return <ItemSummary key={task._id} updateShoppingItem={this.updateCurrentShoppingItem} shoppingItem={task} removeFromCurrentItems={this.removeFromCurrentItems} addToCurrentList={this.addToCurrentList} />

Similar answer here: Change to React State doesn't update display in functional component

sunalive
  • 255
  • 4
  • 13
1

The issue is the update for shoppingItems. You save a reference to the current state object, mutate it, and store it back in state. Spreading this.state.shoppingItems into a new object first will create a new object reference for react to pick up the change of.

React uses shallow object comparison of previous state and prop values to next state and prop values to compute what needs to be rerendered to the DOM and screen.

removeFromCurrentItems(shoppingItem) {
  const items = this.state.shoppingItems.currentShoppingItems.filter(item => item._id !== shoppingItem._id);

  const shoppingItems = {...this.state.shoppingItems};
  shoppingItems.currentShoppingItems = items;
  shoppingItem.number = 0;
  shoppingItem.completed = false;
  shoppingItems.previousShoppingItems.push(shoppingItem);
  this.setState({
    shoppingItems: shoppingItems
  });
  // call to API to update in database
}
Drew Reese
  • 165,259
  • 14
  • 153
  • 181
  • Thanks, I tried this but unfortunately, it is still producing the same output where the objects change correctly but the display hasn't updated properly – sunalive Apr 17 '20 at 08:18
  • Any other places in your component you set state? – Drew Reese Apr 17 '20 at 08:30
  • There are a few, ones which modify the state like the removeFromCurrentItems I updated to use the same line you changed in the code and then there is the componentDidMount which calls the API and upon a result sets the initial shoppingItems – sunalive Apr 17 '20 at 08:48
  • The error only occurs if I remove an item which isn't the last item in the array – sunalive Apr 17 '20 at 08:51
  • @sunalive A lot of moving parts for removing an item from an array. Can you post a minimal codesandbox that reproduces this issue? Would be quicker to debug. – Drew Reese Apr 17 '20 at 08:56
  • Sorry this is the only part which removes the item from an array – sunalive Apr 17 '20 at 09:00
  • https://codesandbox.io/s/react-example-q423e here is a basic example excuse the formatting etc – sunalive Apr 17 '20 at 09:25
  • @sunalive Is it possible to add a little README to that sandbox just to give a quick overview of how the UI should work? – Drew Reese Apr 17 '20 at 09:33
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/211859/discussion-between-sunalive-and-drew-reese). – sunalive Apr 17 '20 at 09:57
1

I had a similar issue with my application in which I had to delete comments made.

<textarea disabled key={note._id} className="form-control">{note.note}</textarea>

after delete, the list was not updating even though I was getting the correct data from the state

But the issue got resolved when I added the Key attribute to the list item.

Vinay Guda
  • 55
  • 1
  • 1
  • 9