3

I have this class:

class Board {
    this.state = {
        lists : [{
            id: 0, 
            title: 'To Do',
            cards : [{id : 0}]
        }]
    }

And want to use setState on the 'cards' array inside of the 'lists' state array. Previously, I had the cards array in a child component but I have now moved it up to the Board class. This is the function that I had before.

deleteCards(id){
    this.setState({
        cards: this.state.cards.filter(card => card.id !== id)
    });
}

How can I change it so that it works now that cards is inside another array?

I was unable to solve it looking at these posts:

ReactJS - setState of Object key in Array

How to edit an item in a state array?

D. Seah
  • 4,472
  • 1
  • 12
  • 20
Chick Evans
  • 47
  • 1
  • 8

2 Answers2

5

To do it all within setState (note that the first argument to setState is an updater function where its first argument is a reference to the previous state):

If you can provide the listId from the caller:

deleteCards(listId, cardId) {
  this.setState(prevState => ({
    lists: prevState.lists.map((list) => {
      if (list.id !== listId) {
        return list
      }

      return {
        ...list,
        cards: list.cards.filter(card => card.id !== cardId) 
      }
    })
  }))
}

If you can not provide the listId from the caller:

deleteCards(id) {
  this.setState(prevState => ({
    lists: prevState.lists.map((list) => {
      if (list.cards.some(card => card.id === id)) {
        return {
          ...list,
          cards: list.cards.filter(card => card.id !== id) 
        }
      }

      return list
    })
  }))
}
chrisbot
  • 335
  • 3
  • 10
  • Using this function doesn't cause an error but it doesn't cause anything to happen. deleteCards is passed down to a button where it is called with an onClick. I can confirm the button is working because it writes to console. – Chick Evans Jul 20 '18 at 01:17
  • I realized I made the assumption that the `id` of the card you want to delete is the same as the `id` of the list it is inside. Are you able to provide the list id to this function as well? If not, this function will have to iterate through each list until it finds a card with the provided id. – chrisbot Jul 20 '18 at 01:24
  • I've updated my answer to reflect both possibilities. – chrisbot Jul 20 '18 at 01:31
  • Thank you I was able to pass both id's and it worked as intended. Would the 'prevState' updater function be necessary if I wanted to add to the 'card' array? As in update the deleteCards function and replace filter with cards : list.cards.concat([{id: cID}]) ? I imagine so. – Chick Evans Jul 20 '18 at 02:57
  • Using a reference to the previous state is generally considered best practice when accessing the state within `setState`. Also, I would avoid mutating the `list.card` array with `concat` and instead use the spread operator (`...`) like so: `cards: [...list.cards, {id: cID}]`. – chrisbot Jul 20 '18 at 15:02
1

You should attempt to use the new rest and spread syntax...

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax

const newListItem = {this.state.lists[0].cards.filter....} 

this.setState({lists: [...this.state.lists.cards, newListItem]})

I would have made this a comment but it would be pretty hard to read. This is just an example you need to actually write a filter.

Gavin Thomas
  • 1,827
  • 2
  • 11
  • 17
  • This returned a "this is a reserved word error" after const newListItem (I replaced filter... with the filter I wrote above). Is there syntax to fix this? – Chick Evans Jul 20 '18 at 01:24