0

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;
3
  • never saw - const test = ([], data) before - what's that? Commented Sep 10, 2020 at 8:31
  • @andymccullough developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… Commented Sep 10, 2020 at 8:32
  • nice, didnt realise it was a thing, but it makes sense when thinking of the parenthesis in a for loop. Still, what's it doing in this example? i.e. [] by itself isn't much of an operation, neither is datas Commented Sep 10, 2020 at 8:36

2 Answers 2

3

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);
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you helped. This helped me out for the moment. @Nico_ 's method combined resolved my next problem with the Index. Thank you guys :D
1

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);
}

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.