0
votes

I am trying to remove an item from an array.

A simple example, parent creates and array of children.

const Parent = () => {

    const [content, setContent] = useState([]);

    useEffect(() => {});

    const addContent = event => {
        setContent(content => content.concat(
          <Child key={content.length} id={content.length} removeItem={(id) => removeContent(id)}/>
        ));
    }

    function removeContent (id) {
        setContent(content.slice(id, 0));
    }

    return(
        <div onClick={(event) => addContent(event)}>
            {content}
        </div>
    )
}

Child has a remove button.

const Child = ({id, removeItem}) => {

    remove = event => {
        removeItem(id);
    }

    return(
       <button onClick={(event) => remove(event)}>
            Remove
       </button>
    )
}

The Problem

Lets say I create 4 children in my array:
[0: {child1}, 1: {child2}, 2: {child3}, 3: {child4}]

I'll remove child3 (index 2), by clicking the remove button of child2.

It goes to my parent removeContent, but my array looks like this:
[0: {child1}, 1: {child2}]

this then deletes my entire array. Does anyone know why?

2

2 Answers

1
votes

There are few issues with your code :

1) You are listening add/remove both event on single click

<div onClick={(event) => addContent(event)}> // <---- listening to add
      // Arry of child which has remove , so on click it will trigger both remove and add (for parent)
      {content} 
     // so 
</div>

// {content}  should be out side of that div

2) slice return new sub array, slice of array it will not provide array with removed id , instead of that you can use filter (with id) or splice(with index)

3) You should not store jsx inside your state ( Do Read )


WORKING SNIPPET :

You can run the below code snippet and review the code changes.

const { useState , useEffect } = React;

const Child = ({id, index, removeItem}) => {

    return(
       <button onClick={() => removeItem(index)}>
            {id} - Remove
       </button>
    )
}

var contentId = 0;
const Parent = () => {

    const [content, setContent] = useState([]);

    useEffect(() => {});

    const addContent = event => {
        contentId++;
        setContent(content => [...content , contentId]);
    }

    function removeContent (index) {
        let clone = [...content]
        clone.splice(index, 1)
        setContent(clone);
    }

    return(<div>
        <div onClick={(event) => addContent(event)}>
            Add Content
        </div>
        {
          content.map((id,i) => 
            <Child key={id} id={id} index={i} removeItem={removeContent}/>
          )
        }
        </div>
    )
}

ReactDOM.render(<Parent />, document.getElementById('react-root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react-root"></div>
0
votes

This is happening because you are using slice to remove item. Your slice is taking two values, first is start and other is end. You are starting at the id index and removing all on the right and then going to 0th index. So all your items are removed from start to end.

arr.slice([start[, end]])

A better solution to remove items from array and that too immutably is using Array.filter approach.

// Function to remove selected array index from existing array.

const removeSelectedItem = (arr, index) => {
   return arr.filter((el, i) => index !== i)
}

This function will remove the selected item from array. arr -> your array. index -> index of item to be removed.

Hope this answers your question.