2

I have an array of objects in todos state hook. And I want to change a single property if it is completed. Seems I can update it but without using setTodos. I am a React beginner.

  const [todos, setTodos] = useState([]);
  const [input, setInput] = useState("");

  const addTodoHandler = (e) => {
    e.preventDefault();
    if (input.length < 2) return;
    setTodos([...todos, { id: Date.now(), text: input, isComplete: false }]);
    setInput("");
  };

  const removeHandler = (id) => {
    setTodos(todos.filter((todo) => todo.id !== id));
  };

 const completeHandler = (id) => {

    // working without setTodo()
    // errors when added setTodo()
     todos.map((todo) =>
       todo.id === id ? console.log((todo.isComplete = !todo.isComplete)) : ""
     );

  };

      <div className="todolist">
        {todos.map((todo) => (
          <Todo
            key={todo.id}
            id={todo.id}
            text={todo.text}
            removeHandler={removeHandler}
            completeHandler={completeHandler}
            isComplete={todo.isComplete}
          />
        ))}
      </div>
3
  • Does this answer your question? How to use `setState` callback on react hooks Commented May 9, 2020 at 6:28
  • Can you share the error log? Commented May 9, 2020 at 6:29
  • TypeError: Cannot read property 'id' of undefined 47 | <div className="todolist"> 48 | {todos.map((todo) => ( 49 | <Todo > 50 | key={todo.id} | ^ 51 | id={todo.id} 52 | text={todo.text} 53 | removeHandler={removeHandler} when added setTodos() :( Commented May 9, 2020 at 6:32

1 Answer 1

7

To fix this inside completeHandler() first create a new array using map() method and inside map() method update the isComplete for the current todo and simply return the updated value like:

var updatedTodos = todos.map((todo) => todo.id === id ? {
  ...todo,
  isComplete: !todo.isComplete
} : todo);

Then inside setTodos() just return this new updatedTodos array like:

setTodos(updatedTodos);

You can also do this in one-line like:

setTodos(todos.map((todo) => todo.id === id ? { ...todo, isComplete: !todo.isComplete } : todo));

But the previous code provides more readability and also helps in better debugging if you want to check each variable line by line.

Sign up to request clarification or add additional context in comments.

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.