0

Why does this not work? If I console.log the todo.completed, it changes but changes again to the original value.

handleChange(id) {
  this.setState(prevState => {
    const updatedTodos = prevState.todos.map(todo => {
      if (todo.id === id) {
        todo.completed = !todo.completed
      }
      return todo // Puts todo item in updatedTodos array in the same index
    })
    return {
      todos: updatedTodos
    }
  })
}
Hao Wu
  • 17,573
  • 6
  • 28
  • 60
worknovel
  • 73
  • 9

2 Answers2

1

This is because you are mutating the object, which is bad in react and lead to unexpected results

handleChange(id) {
    this.setState(prevState => {
    const updatedTodos = prevState.todos.map(todo => {
        if (todo.id === id) {
            // todo.completed = !todo.completed
            //mutating, when mutating react doesn't understand it's a new entity

            //you have to create a new object based on the todo and change the props as you want
            return {
                ...todo,
                completed: !todo.completed
            }
        }
        return todo // Puts todo item in updatedTodos array in the same index
    })
    return {
        todos: updatedTodos
    }
    })
}
Kalhan.Toress
  • 21,683
  • 8
  • 68
  • 92
  • @worknovel if you are not familire with spread operator read it here, https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax when developing with react this will be really helpful – Kalhan.Toress Oct 09 '20 at 06:26
0

You are mutating the todo object directly which can lead to weird behavior.

Instead of changing the todo in your condition, you will want to return a new todo.

return { ...todo, completed: !todo.completed }

More details here https://redux.js.org/recipes/structuring-reducers/immutable-update-patterns#updating-an-item-in-an-array

jens
  • 2,075
  • 10
  • 15