Why doesn't component state change in React?

  • 0
    Hello, I don't understand why the state of the checkboxes does not change when clicked, the most interesting thing is, if you replace todo.completed with todo.text and change the text, then the state will be changed, also if you add console.log ("Clicked", id), then it will output the word Clicked and the id of the checkbox. I would be very happy if you can help me figure it out.
    Here is the parent component code:

    import React, { Component } from 'react'
    import TodoItem from "./TodoItem"
    import todosData from "./todosData"
    
    class App extends Component  {
      
        constructor() {
            super()
            this.state = {
                todos: todosData
            }
            this.handleChange = this.handleChange.bind(this)
        }
        
        handleChange(id) {
          this.setState(prevState => {
              const updatedTodos = prevState.todos.map(todo => {
                  if (todo.id === id) {
                      todo.completed = !todo.completed
                  }
                  return todo
              })
              return {
                  todos: updatedTodos
              }
          })
      }
        render() {
          const todoItems = this.state.todos.map(item => <TodoItem key={item.id} item={item} handleChange={this.handleChange}/>)        
            return (
                <div className="todo-list">
                    {todoItems}
                </div>
            )    
        }
    }
    
    export default App

    Here is the child component code:

    import React from "react"
    
    function TodoItem(props) {
        return (
            <div className="todo-item">
                <input 
                    type="checkbox" 
                    checked={props.item.completed} 
                    onChange={() => props.handleChange(props.item.id)}
                />
                <p>{props.item.text}</p>
            </div>
        )
    }
    
    export default TodoItem


    Here's the JSON file where everything comes from:
    const todosData = [
        {
            id: 1,
            text: "Take out the trash",
            completed: true
        },
        {
            id: 2,
            text: "Grocery shopping",
            completed: false
        },
        {
            id: 3,
            text: "Clean gecko tank",
            completed: false
        },
        {
            id: 4,
            text: "Mow lawn",
            completed: true
        },
        {
            id: 5,
            text: "Catch up on Arrested Development",
            completed: false
        }
    ]
    
    export default todosData
    JavaScript Aidan Barnett, Oct 31, 2019

  • 2 Answers
  • 0
    Stitching

    todo.completed =! todo.completed

    is executed on every click twice, so first the value becomes false, then true again, while the text variable changes nicely. I'm a little ashamed, because I don't know exactly how the reactant works in this case, but there are two ways out:

    1)
    if (todo.id === id) return { ...todo, completed: !todo.completed }
    return todo




    Which is actually more correct, since every mutable element in the react should change the reference when changed.



    2) Calculate new completed immediately

    onChange={() => props.handleChange(props.item.id, !props.item.completed)}




    and use the resulting value in the function.

    handleChange(id, newCompleted) {
    this.setState(prevState => {

    const updatedTodos = prevState.todos.map(todo => {
    if (todo.id === id) {
    todo.completed = newCompleted
    }
    return todo
    })
    return {
    todos: updatedTodos
    }
    })
    Anonymous

  • 0
    handleChange(id) {
    this.setState(prevState => {
    const updatedTodos = prevState.todos.map(todo => {
    if (todo.id === id) {
    return { ...todo, completed: !todo.completed }
    }
    return todo
    })
    return {
    todos: updatedTodos
    }
    })
    }
    Anonymous

Your Answer
To place the code, please use CodePen or similar tool. Thanks you!