MisterLA
MisterLA

Reputation: 101

Trying to splice items from my array in ReactJS

I'm trying to splice on a DoubleClick event an item from my list(inventory) but something is not working as I want it. Would be nice if someone could be so kind and help me out to figure out what I'm doing wrong here. For the Info: when I try to slice an item it gets sliced but it is every time the first item and the second item loses all the content inside:

    function Inventory() {
    const [datas, setData] = useState([
      {
        id: 1, 
        label: "Sword",
        itemname: "grey_sword",
        pieces: 1,
        type: "weapon",
      },
      {
        id: 2, 
        label: "Knife",
        itemname: "grey_knife",
        pieces: 1,
        type: "weapon",
      },
    ]);

    useEffect(() => {
      const getItems = (data) => {
        setData(data);
      } // this section is for something else
    }, [datas]);

    const deleteItem = (index) => {
      const test = ([], datas)
      test.splice(index, 1)
      setData([{test : datas}]);
    }



    const renderItem= (data, index) => {
      return (
        <Item
          key={data.id}
          id={data.id}
          type={data.type}
          label={data.label}
          index={index}
          name={data.itemname}
          pieces={data.pieces}
          deleteItem={deleteItem}
        />
      )
    }

    return (
        <div className="inventory-holder">
            <div className="inventory-main">
              <div className="inventory-information">
                <div className="inventory-title">
                  Inventory
                </div>
                <div className="inventory-weight-info">
                  0.20 kg / 1.00 kg
                </div>
                <div className="inventory-buttons">
                  <button className="refresh-button" tabIndex="-1"><FontAwesomeIcon icon={faRedo} /></button>
                  <button className="close-button" tabIndex="-1"><FontAwesomeIcon icon={faTimes} /></button>
                </div>
              </div>
              <div className="items-holder">
                <div>{datas.map((data, i) => renderItem(data, i))}</div>
              </div>
          </div>
        </div>
    )
}

export default Inventory;

and that would be the Item:

const Item = ({ index, id, type, label, name, pieces, deleteItem }) => {
  
    const useItem = e => {
      const type = e.target.getAttribute("itemType");
      const index = e.target.getAttribute("data-index");
      const pieces = e.target.getAttribute("itempieces");
      console.log(type + " " + index + " " + pieces )
      if(parseInt(pieces) <= 1){
        deleteItem(parseInt(index));
      }
    }

    return(
        <div data-index={id} onDoubleClick={useItem} className="inventory-item" itemType={type} itemname={name} itemlabel={label} itempieces={pieces}>
            <img className="item-pic" src={chosedtype} ></img>
            <div className="item-label">{label}</div>
            <div className="item-number-pieces">{pieces}</div>
        </div>
    );
};

export default Item;

Upvotes: 0

Views: 738

Answers (2)

Nico_
Nico_

Reputation: 1386

Your Item is way too complicated:

You can directly use the props without passing them through your div.

const Item = ({ index, id, type, label, name, pieces, deleteItem }) => {
  
    const useItem = () => {
      console.log(type + " " + index + " " + pieces )
      if(pieces <= 1){
        deleteItem(index);
      }
    }

    return(
        <div data-index={id} onDoubleClick={useItem} className="inventory-item">
            <img className="item-pic" src={chosedtype} ></img>
            <div className="item-label">{label}</div>
            <div className="item-number-pieces">{pieces}</div>
        </div>
    );
};

export default Item;

Then your deleteItem function doesn't do what you want:

const deleteItem = (index) => {
  const test = ([], datas); //test = datas;
  test.splice(index, 1); // test = test without the item at the index
  setData([{test : datas}]);//data = [{test: datas}] so an array with an object with the property test = datas (the original array).
}

You should change your deleteItem to something like:

const deleteItem = (index) => {
    const newArray = datas.filter((item, i) => i !== index);
    setData(newArray);
}

Upvotes: 1

Drew Reese
Drew Reese

Reputation: 203091

Issue

Array::splice does an in-place mutation.

The splice() method changes the contents of an array by removing or replacing existing elements and/or adding new elements in place.

The main issue here is state mutation.

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

const test = ([], datas) ends up saving the state reference data to test, which is then mutated by test.splice(index, 1), and then strangely enough is overwritten back into state differently setData([{ test: datas }]);.

Solution

A common pattern is to use array::filter instead and filter on the index. filter returns a new array.

const deleteItem = (index) => {
  setData(datas => datas.filter((_, i) => i !== index);
}

Upvotes: 3

Related Questions