-1

I am learning react hooks and I am just trying to do a simple function to remove the item from the list. To do this I am using find, indexOf, and splice.

In the onClick function, I am using the indexOf in the array.splice(indexOf, 1), BUT it returns just the item from the list. Everything rerenders and does what it is supposed to do, but the only itme that renders is the item that I just tried to delete. What am I missing?

const [todos, setToDo] = useState(initialToDo);
const [input, setInput] = useState('');

const todoList = (todos) => {
    return (
        todos.map((todo) => {
        return (
            <div className='todo-list flex p-2 w-1/2 justify-between'>
                <p className="px-3">{todo.name}</p>
                <button 
                    className='rounded-sm border-2 px-2'
                    onClick={(e)=>{
                        let item = todos.find(el=>el.id == todo.id);
                        console.log(item)
                        let index = todos.indexOf(item);
                        console.log(index)
                        todos = todos.splice(index, 1)
                        // todos == item
                        setToDo(todos)
                    }}    
                >-</button>
            </div>
    )}))
}
GalAbra
  • 4,282
  • 4
  • 18
  • 34
AvidDabbler
  • 203
  • 1
  • 8
  • 2
    Have you reviewed [the documentation for `.splice()`?](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice) – Pointy Nov 30 '20 at 15:15
  • 1
    `splice` returns the element(s) that was removed - not the updated array – GalAbra Nov 30 '20 at 15:16
  • splice gives you the element you "spliced out" splice alone does the exact opposite – BeeTheKay Nov 30 '20 at 15:17
  • You can use `Array.prototype.filter()`, although it's a bit more complicated that splice. Also, `splice` modifies the original array, so just don't reassign `todos` to be the return of the `splice`, just have that be a line of its own. – Samathingamajig Nov 30 '20 at 15:18
  • 1
    @Samathingamajig is it more complicated? It does *exactly* one job and it does it exactly the same every time. Splice has at least three different effects you can use it for, if not more. The syntax you use will greatly differ depending on which one you need. And even if you call `.splice()` correctly you can still shoot yourself in the foot as the MANY questions about `.splice()` on this very site show. A very common problem is using `.splice()` in a forward loop. I'm not really sure why you consider this "simpler" or "easier". – VLAZ Nov 30 '20 at 15:21
  • I have reviewed the docs for splice and have replicated a solution that was given on StackOverflow https://stackoverflow.com/questions/5767325/how-can-i-remove-a-specific-item-from-an-array – AvidDabbler Nov 30 '20 at 15:21
  • @VLAZ While splice is weird, I would say that `filter` is more complicated as it requires you to make your own callback function. Splice you just need to answer simple questions: "What index?", "How many elements do you want to remove?", and "What elements (if any) do you want to insert at the given index?". (Although I use filter way more often as it's an easier return in a one-liner. – Samathingamajig Nov 30 '20 at 15:27

3 Answers3

3

Yes, Array.splice returns the removed element and mutates the original array, which mean you can use index to delete/update the todo from todos list.

Simplest way of doing this, is the following way. Here's the working example

const todoList = () => {
  const [todos, setToDo] = useState(initialToDo);
  const [input, setInput] = useState('');

  const handleDelete = index => {
    todos.splice(index, 1)
    setToDo([...todos])
  }

  return (
    todos.map((todo, index) => {
    return (
      <div className='todo-list flex p-2 w-1/2 justify-between'>
        <p className="px-3">{todo.name}</p>
        <button 
          className='rounded-sm border-2 px-2'
          onClick={() => handleDelete(index)}    
        >
        -
       </button>
      </div>
  )}))
}
Naren
  • 2,976
  • 3
  • 9
  • 20
0

splice returns the deleted items. I recommend using filter instead, something like:

setToDo(todos.filter(({ id }) => id != todo.id));
Camilo
  • 4,034
  • 24
  • 39
0

Use filter instead of mutating with splice. Try this snippet.

const TodoList = () => {
  const [todos, setTodos] = React.useState([
    { name: 'a', id: 1 },
    { name: 'b', id: 2 },
  ]);
  return todos.map((todo) => {
    return (
      <div>
        <p>{todo.name}</p>
        <button onClick={() => setTodos(todos.filter(item => item.id !== todo.id))} > - </button>
      </div>
    );
  });
};

const domContainer = document.querySelector('#app');
ReactDOM.render(<TodoList />, domContainer);
<script crossorigin src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>

<div id="app"> </div>
Siva K V
  • 7,622
  • 2
  • 11
  • 24