Почему флажки не меняются с отмеченных на непроверенные при нажатии?

#javascript #reactjs

#javascript #reactjs

Вопрос:

Мое приложение React работает не так, как должно быть. Проблема в том, что флажки вообще не меняются. Мне удалось показать флажки (те, у которых есть свойство completed=true ), и при отладке кажется, что при нажатии он работает нормально, но по какой-то причине поле, которое необходимо изменить, автоматически изменяется само по себе.

У вас есть какие-либо идеи, почему?

 //APP.JS
import React from "react"

import './App.css';
import Header from "./Header"
import TodoItem from "./todoItem";
import todosData from "./todosData"


class App extends React.Component {
    constructor() {
      super()
      this.state = {
        todos: todosData
      }
      this.handleChange = this.handleChange.bind(this)
    }

    handleChange(id) {
      this.setState((prevState) => {
        const newArray = prevState.todos.map((elem) => {
          if(elem.id === id) {
            elem.completed = !(elem.completed)
          }
          return elem
        })
        return {
          todos: newArray
        }
      })
    }

    render() {
      const todosArray = this.state.todos.map(item => 
          <TodoItem
              key={item.id} 
              item={item}
              handleChange={this.handleChange}
          />)

      return (
        <div className="App">
              <Header />
              <div className="container">
                  {todosArray}
              </div>
        </div>
      )
    }
}

export default App;


//TODOITEM.JS
import React from "react"

function TodoItem(props) {
    return (
        <div className="elem-container">
            <input type="checkbox"
                checked={props.item.completed}
                onChange={() => props.handleChange(props.item.id)}
            />
            <span className="span-container">{props.item.text}</span>
        </div>
    )
}

export default TodoItem

//TODOSDATA.JS
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
  

Заранее благодарю вас за помощь

Ответ №1:

вам нужно изменить две вещи, и сначала все будет работать нормально: внутри todoItem.js

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

второе:
внутри родительского файла

 handleChange(event, id) {
  this.setState((prevState) => {
    const newArray = prevState.todos.map((elem) => {
      if(elem.id === id) {
        elem.completed = event.target.checked
      }
      return elem
    })
    return {
      todos: newArray
    }
  })
}
  

теперь все будет работать так, как вы ожидали
, хорошего дня

Ответ №2:

Я не эксперт, поскольку сам изучаю React, но, глядя на код handleChange (id), в его операторе ‘if’ нет состояния else, вы пробовали добавлять?

Ответ №3:

Добавив к ответу @mouheb, вы можете упростить еще один шаг. вам не нужно map использовать все элементы для обновления одного элемента. вы можете изменить непосредственно элемент (если он изменяемый).

 // todoItem.js
onChange={(e) => props.handleChange(e, props.item) }

  
 // parent file

handleChange(event, prop) {
  prop.completed = event.target.
  this.setState({ todos: this.state.todos }) or this.setState({ todos: [...this.state.todos] })
}