0

In a small React app, I'm trying to add delete functionality via a button for a list. Presently, I'm attempting this through the deleteItem function, which makes use of array.splice prototype method.

However, I'm encountering the error, Too many re-renders. React limits the number of renders to prevent an infinite loop.. What is the cause of this error? Shouldn't this function only be invoked once, when the button is clicked?

And how can I resolve this error?

import "./styles.css";
import React, { useState, Fragment } from "react";

export default function App() {
  const [items, setItems] = useState(["first item"]);
  const [newItem, setNewItem] = useState("");

  const handleSubmit = (event) => {
    event.preventDefault();
    setItems([newItem, ...items]);
  };

  const handleChange = (event) => {
    setNewItem(event.target.value);
  };

  const deleteItem = (i) => {
    setItems(items.splice(i,1))
  }

  return (
    <div>
      <form>
        <input type="text" value={newItem} onChange={handleChange} />
        <input type="button" value="submit" onClick={handleSubmit} />
      </form>
      <ul>
        {items.map((i) => {
          return (
          <Fragment>
            <li>{i}</li>
              <button
                onClick= {() => deleteItem(i)}> // Amr recommendation
                delete 
              </button>
          </Fragment>
          );
        })}
      </ul>
    </div>
  );
}

Edit: I've taken user, Amr's, recommendation and added a anonymous arrow function to the button. However, a new issue has arisen. I can delete any item up until there exists only one item in the array. The final item cannot be deleted. Why is this?

4
  • you are passing function reference, change it to an arrow function that triggers the delete method onClick= {()=>deleteItem(i)}> Commented Apr 15, 2022 at 14:33
  • @Amr, 1/ for my long term react/js growth, why does this make a difference? Commented Apr 15, 2022 at 14:35
  • @Amr and 2/ this introduces a new complication. If the length of the array >= 2, I can delete any items w/o issues. However, if the array length = 1, the only item cannot be deleted. Any thoughts on this behavior? Commented Apr 15, 2022 at 14:36
  • setItems(items.splice(i,1)) <-- may I know why this is being done? Array .splice() documentation says: Return value -> An array containing the deleted elements.. Essentially, the 1 item removed at index i is being stored using setItems - in other words all items except the 1 item are effectively deleted. Commented Apr 15, 2022 at 14:49

2 Answers 2

2

you are passing function reference on the onClick handler, change it to an arrow function that triggers the delete method onClick= {()=>deleteItem(i)}>

second thing is that you should add keys to your the parent component when you Map over components to prevent unnecessary behavior.

and the last thing is that in your delete method, you are using Array.prototype.splice(), which returns the item that will be removed, from the items, your requested/ required behavior can be achieved through the Array.prototype.filter() method

  const deleteItem = (i) => {
    setItems(items.filter((item) => item !== i));
  };

This is the final result, it should work fine.

import React, { useState, Fragment } from "react";

export default function App() {
  const [items, setItems] = useState(["first item"]);
  const [newItem, setNewItem] = useState("");

  const handleSubmit = (event) => {
    event.preventDefault();
    setItems([...items, newItem]);
  };

  const handleChange = (event) => {
    setNewItem(event.target.value);
  };

  const deleteItem = (i) => {
    setItems(items.filter((item) => item !== i));
  };
  console.log(items);
  return (
    <div>
      <form>
        <input type="text" value={newItem} onChange={handleChange} />
        <input type="button" value="submit" onClick={handleSubmit} />
      </form>
      <ul>
        {items.map((i, idx) => {
          return (
            <div key={idx}>
              <li>{i}</li>
              <button onClick={() => deleteItem(i)}>delete</button>
            </div>
          );
        })}
      </ul>
    </div>
  );
}
Sign up to request clarification or add additional context in comments.

Comments

0

you can use following code for deleting from an array. it copies 'items' array and delete one item and after that setstate new array. it prevent re-render whole component,do operations on copy of state and setstate final result.

  const deleteItem = (i) => {
     let newItems=[...items]
     newItems.splice(i,1)
     setItems(newItems)
  };

3 Comments

Should one be assigning the value of newItems when there is a hook for that already instantiated, specifically the setNewItems function?
Yes we should create a new copy of the items array after every deletes, and treated it as immutable. This will allow us to store every past version of the items array. Because states are immutable and the whole component re-render on every set state.
in react website and its example about state, copies an array with splice() and then set state its copy. You can check it out reactjs.org/tutorial/…

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.