-1

I'm making simple todo list in react, and when i delete a task it doesnt update immediately, but when i make a change in input, I don't know why it happens. Tried to change how deleteTask works but i didnt found the solution.

form.jsx

import { useState } from 'react';
import './styles/form.css';
import Tasks from './tasks';

function TaskForm() {
  const initialList = [{task: 'Do something', done: false}];
  const [tasks, setTasks] = useState(initialList);
  const [input, setInput] = useState('');
  const [validTask, setValidTask] = useState('valid');
  const addTask = () => {
    if(input.length !== 0) {
      setValidTask('valid');
      setTasks(tasks.push({task: input, done: false}));
      setTasks(tasks);
      setInput('');
    }
    else {
      setValidTask('invalid');
    }
    console.log(tasks);
  }
  return (
    <>
      <div className='maindiv'>
        <p>Task app</p>
        <input maxLength={32} value={input} placeholder='add a new task...' onChange={e => setInput(e.target.value)}/><br />
        <p style={{color: 'red'}} className={validTask}>Task can't be empty</p>
        <input type='submit' value='Add task' onClick={addTask}/>
      </div>
      <Tasks tasks={tasks}/>
    </>
  );
}

export default TaskForm;

tasks.jsx

import { useState } from 'react';
function Tasks(props) {
  const [tasks, setTasks] = useState(props.tasks);
  const deleteTask = (index) => {
    tasks.splice(index, 1);
    setTasks(tasks);
    
  };
  const taskList = props.tasks.map(task => (
    <li key={task.id}>
      <input type='checkbox' value={task.done} /> 
      {task.task}
      <input type='button' value='delete' onClick={() => deleteTask(task.id)} />
    </li>
  ));
  return <ul>{taskList}</ul>;
}

export default Tasks;
xoxoen21
  • 1
  • 2
  • Does this answer your question? [How to delete an item from state array?](https://stackoverflow.com/questions/36326612/how-to-delete-an-item-from-state-array) – Konrad Jun 19 '23 at 13:45
  • Mutating state will cause skipped renders. Treat it as a red flag anytime you call `setState(oldState)` like you are with `setTasks(tasks)`. `splice` updates the array in place, meaning it mutates the original state array. You'll need to make a copy of the array and then delete the element – Brian Thompson Jun 19 '23 at 13:46

2 Answers2

1

You can't splice arrays in React states as clearly described in the docs

const deleteTask = (index) => {
    setTasks(tasks => [...tasks.slice(0, index), ...tasks.slice(index+1)]);
};

or using filter:

const deleteTask = (index) => {
    setTasks(tasks => [...tasks].filter((_, i) => i === index));
};
Asplund
  • 2,254
  • 1
  • 8
  • 19
  • It's still not working, I'm wondering if `const [tasks, setTasks] = useState(props.tasks);` doesnt cause error, i dont have any other idea – xoxoen21 Jun 19 '23 at 15:35
1

You're not updating state, you're mutating state:

tasks.splice(index, 1);
setTasks(tasks);

According to the documentation:

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

So instead of creating a new array reference, you're modifying the existing array reference and setting state back to that same reference. Since the reference doesn't change, React doesn't see that the state was "updated". Which is why mutating state leads to bugs like this.

Create a new array reference, modify that, then update state to that:

let newTasks = [...tasks];
newTasks.splice(index, 1);
setTasks(newTasks);
David
  • 208,112
  • 36
  • 198
  • 279