Array splice removing wrong item or multiple ones at once

Viewed 592

Hi I know this is a very basic problem, but my code doesn't want to work correctly. I've tried removing some items from an array stored in this.state but the function just do different things than I expect, sometimes it removes wrong item and recently it started removing more than one item at once, can someone here please review my code and see what's missing?

  deleteProduct = async (index) => {
    this.setState({ loading: true, items: [] })
    let { cart } = this.state
    cart.splice(index, 1)
    console.log('deleted this > :', cart.splice(index, 1));
    this.setState({cart:cart})
    try {
      await AsyncStorage.setItem('cart', JSON.stringify(cart))
      this.setState({ cart: cart, loading: false })
      this.retrieveCart()
    } catch (error) {
      this.setState({ error: error })
      console.log(error.message)
    }
  }

my data looks like this

cart : Array [
  Object {
    "id": 195,
    "price": "69",
    "qty": 1,
  },
  Object {
    "id": 200,
    "price": "69",
    "qty": 1,
  },
  Object {
    "id": 201,
    "price": "110",
    "qty": 1,
  },
]

should I just use a different approach like targeting by id because that index thing is just not working well

2 Answers

What I would do is update the code to reference something unique in the data (like the id field you have). This isn't required but would be less error prone. I'd use a filter here so you don't have array mutation issues between state transitions.

this.setState( {cart: cart.filter( item => item.id !== deleteId )}

where deleteId is the id of the entity the user wishes to delete.

That would look something like this

{ cart.map(item =>
    <CartItem
      key={item.id}
      data={item}
      onDelete={this.deleteProduct}
    />
)}

assuming CartItem calls this.props.onDelete(this.props.data.id)

Remember to double check the method you are using to handle data changes like this. Array::splice mutates the array. Currently you are calling splice twice in the delete function which will remove elements in both calls.


Edit:

your function should look something like this

deleteProduct = async (deleteId) => {
  this.setState({ loading: true, items: [] })
  const cart = this.state.cart.filter( item => item.id !== deleteId )}
  this.setState({ cart })
  try {
    await AsyncStorage.setItem('cart', JSON.stringify(cart))
    this.setState({ loading: false })
    this.retrieveCart()
  } catch (error) {
    this.setState({ error: error, loading: false })
    console.log(error.message)
  }
}

yes. ALWAYS and ONLY delete items by item.id. Never using splice.

also you are now deleting multiple items because you added cart.splice(index, 1)) to your console.log statement. Not good!

Related