@Bizki

Почему не меняется состояние компонента в React?

Здравствуйте, не понимаю, почему не изменяется состояние флажков при клике, самое интересное, если заменить todo.completed на todo.text и изменить текст, то состояние будет изменено, также если добавить console.log("Clicked", id), то оно будет выводить слово Clicked и id флажка. Буду очень рад если поможете разобраться.
Вот код родительского компонента:

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

Вот код дочернего компонента:

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


Вот код JSON-файла откуда всё берётся:
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
  • Вопрос задан
  • 223 просмотра
Решения вопроса 1
@dimoff66
Кратко о себе: Я есть
Строчка
todo.completed = !todo.completed
выполняется при каждом клике дважды, поэтому сначала значение становится false, затем снова true, в то время как текстовая переменная прекрасно меняется. Мне немного стыдно, поскольку точно не знаю механизм работы реакта в данном случае, но выхода тут два:
1)
if (todo.id === id) return { ...todo, completed: !todo.completed }
return todo


Что в действительности более правильно, так как каждый изменяемый элемент в реакте должен менять ссылку при изменении.

2) Вычислять новый completed сразу
onChange={() => props.handleChange(props.item.id, !props.item.completed)}


и уже в функции пользоваться полученным значением
handleChange(id, newCompleted) {
      this.setState(prevState => {
        
          const updatedTodos = prevState.todos.map(todo => {
              if (todo.id === id) {
                todo.completed = newCompleted 
              }
              return todo
          })
          return {
              todos: updatedTodos
          }
      })
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
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
      }
  })
}
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы