1

I'm using this function to remove an item from my state array in React

removeProduct(index) {
    this.setState(prevState => ({
        selectedProducts: update(prevState.selectedProducts, {$splice: [[index, 1]]}),
    }))
}             

it is being passed through like this:

<Basket items={this.state.selectedProducts} removeItem={this.removeProduct.bind(this)}/>

<BasketItem product={product} key={index} remove={this.props.removeItem}/>

and then called like this:

<button onClick={props.remove.bind(this)}>x</button>

but its not removing that specific item. Its only removing the first item in the array.

Can anyone help?

7
  • 1
    You're not passing the index to the function anywhere Commented Jan 28, 2018 at 20:27
  • how should it be passed in? When I try passing it as an argument within the function and the splice it removes the product but keeps the button Commented Jan 28, 2018 at 20:37
  • How are you passing index to BasketItem - where's that coming from in Basket? Commented Jan 28, 2018 at 20:38
  • I thought that index was the basket item. Remove 1 at this index? Commented Jan 28, 2018 at 20:43
  • 1
    No, your BasketItem component has a prop called index - where is that passed to it from? Is it inside the Basket component? Commented Jan 28, 2018 at 20:44

2 Answers 2

4

From your BasketItem (or wherever the button is) you need to lift a unique identifier up to the removeProduct function. I'm assuming the removeProduct is somewhere in a parent of BasketItem.

When the button is clicked, BasketItem's onRemoveProduct is called. That in turn calls it's prop with the id of the the item. The parent (Basket) onRemoveProduct then knows what product to remove the basket.

See code below.

Note: Do not use the index from .map as the key. You need to use some identifying item on the product.

Example: * you have 3 items with index and key = (0,1,2).

  • React renders the 3 items

  • You remove the 2nd item (key = 1) and then the array.map happens again.

  • It returns 2 items with keys = (0,1).

  • React sees that the items have changed and that the item with key = 2 (the last item) is missing.

  • Item 2 (the last item, is removed, leaving the first two in place.

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      products: [
        {
          id: 0,
          name: "Product 1"
        },
        {
          id: 1,
          name: "Product 2"
        },
        {
          id: 2,
          name: "Product 3"
        }
      ]
    };
    this.handleRemoveProduct = this.handleRemoveProduct.bind(this);
  }

  handleRemoveProduct(e) {
    const products = this.state.products.filter(prod => prod.id !== e)
    this.setState({products})
  }

  render() {
    return (
      <div>
        <ul>
          {this.state.products.map((product, index) => {
            return (
              <BasketItem
                key={product.id}
                product={product}
                onRemoveProduct={this.handleRemoveProduct}
              />
            );
          })}
        </ul>
      </div>
    );
  }
}

class BasketItem extends React.Component {
  constructor(props) {
    super(props);
    this.onRemoveProduct = this.onRemoveProduct.bind(this);
  }
  onRemoveProduct(e) {
    e.preventDefault();
    this.props.onRemoveProduct(this.props.product.id)
  }
  
  render() {
    return (
      <li>
        {this.props.product.name}
        <button onClick={this.onRemoveProduct}>X</button>
      </li>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

Sign up to request clarification or add additional context in comments.

Comments

0

It would be great to see your application's full source code, in order to address the problem. Since I can't see the full picture, I have put in a really simplistic example of managing component state, where the key player is a method that removes element from collection held in state by its index - very similar to the one in your code snippet.

import React, { Component } from 'react';
import * as _ from 'lodash';

class Content extends Component {

state = {
    products: [ {id: 1, name: 'some name'}, 
        { id: 2, name: 'some other name'},
        { id: 3, name: 'some other name 2'},
        { id: 4, name: 'other stuff'},
        { id: 5, name: 'other stuff 1'},
        { id: 6, name: 'other stuff 2'}
    ];
}

constructor(props) {

    super(props);
}

removeProduct(index) {
    const products = this.state.products;
    _.pullAt(products, index);
    this.setState({ products: products });
}

render() {
    const { products } = this.state;
    return (
        <div>
            {products.map(n => {
                return (
                    <div key={n.id}>
                        {n.name} <button onClick={(event) => this.removeProduct(products.indexOf(n))}>remove item</button>
                    </div>
                );
            })}
        </div>
    );
}
}

export default Content;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.