Search code examples
reactjsreact-bootstrapreact-bootstrap4-modal

React-Bootstrap modal only show and delete last mapped element


i'm building eccommerce and in my cart i want to show a modal when user tap on delete icon but my modal always show and delete last element of my cart

how can i resolve this issue

here's my modal component:

const VerticalModal = ({ item, mShow, hide, name }) => {
  return (
    <Modal
      show={mShow}
      size="md"
      
      centered
    >
      <Modal.Header>
        <Modal.Title >
          <h6>Remove from cart</h6>
        </Modal.Title>
      </Modal.Header>
      <Modal.Body>
        <p className="text-center">Are you sure you want to remove {name}</p>
      </Modal.Body>
      <Modal.Footer className="d-flex justify-content-between">
        <Button variant="outline-secondary" size="sm" onClick={hide}>
          Cancel
        </Button>
        <Button variant="outline-danger" size="sm" onClick={item}>
          Remove
        </Button>
      </Modal.Footer>
    </Modal>
  );
};

here's my cart code :

{cart &&
  cart.cartItems.length > 0 &&
  cart.cartItems.map((item, index) => (
    <Card
      key={index}
      className=" cart-card-magninn cart-card-shadow"
    >
      <Row className="p-3">
        <Col>{item.img}</Col>
        <Col>{item.name}</Col>       

        <Col md={2} xs={2}>
          <button
            onClick={() => setModalShow(true)}
          >
            <FontAwesomeIcon icon={faTrashAlt} />
          </button>
          <VerticalModal
            mShow={modalShow}
            hide={() => setModalShow(false)}
            item={() => removeFromCartHandler(item.prodid)}
            name={item.prodname}
          />
        </Col>
        </Row>
        )}

Solution

  • You're creating four modals and whenever, the modal opens, it has the value of the last item. You should move modal out of the map function and store the selected item in a separate state and use that to delete the info.

    Initialize the selected item as empty object.

    const [selectedItem, setSelectedItem] = useState({})
    

    Then, update the click method on the button.

    <button
      onClick={() => {
        setModalShow(true)
        setSelectedItem(item)
      }}>
      <FontAwesomeIcon icon={faTrashAlt} />
    </button>
    

    After that, move the modal code outside of the map function.

    {modalShow ? 
      <VerticalModal
        mShow={modalShow}
        hide={() => {
          setModalShow(false)
          setSelectedItem({})
        }}
        item={() => {
           removeFromCartHandler(selectedItem.prodid)
           setSelectedItem({})
        }
        name={selectedItem.prodname}
      />
    : null}
    

    Updated code could be something like this

    {cart &&
      cart.cartItems.length > 0 &&
      cart.cartItems.map((item, index) => (
        <Card
          key={index}
          className=" cart-card-magninn cart-card-shadow"
        >
          <Row className="p-3">
            <Col>{item.img}</Col>
            <Col>{item.name}</Col>       
            <Col md={2} xs={2}>
              <button
                onClick={() => {
                  setModalShow(true)
                  setSelectedItem(item)
                }}>
                <FontAwesomeIcon icon={faTrashAlt} />
              </button>
            </Col>
            </Row>
       )}
       
       {modalShow ? 
        <VerticalModal
          mShow={modalShow}
          hide={() => {
            setModalShow(false)
            setSelectedItem({})
          }}
          item={() => {
           removeFromCartHandler(selectedItem.prodid)
           setSelectedItem({})
          }
          name={item.prodname}
          />
      : null}