首页 > 解决方案 > Checkbox 在 React todo 应用程序中单击时不会更改其值

问题描述

请帮我解决这个问题,我不明白我在哪里做错了。因此,当我单击复选框时,值不会改变(如果默认情况下true,当我单击单击时它应该是false)。为此,我onChangetodoList组件中调用handleClick函数,我更改了todo.completed值(基本上是切换值)。

方法App.js 内部handleClickconsole.log(todo)从地图函数返回之前做的时候可以正常切换,但它没有在updatedTodo.

应用程序.js

import TodosData from "./todoData";
import TodoList from "./todoList";
import "./styles.css";

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

  handleChange(id) {
    this.setState(prevState => {
      const updatedTodo = prevState.todos.map(todo => {
        // console.log(updatedTodo);
        if(todo.id === id) {
          console.log("before the opt "+todo.completed);
          todo.completed = !todo.completed
          console.log("after the opt "+todo.completed);
        }
        //console.log(todo);
        return todo;
      })
      console.log(updatedTodo);
      return {
        todos: updatedTodo
      }
    });
  }

  render() {

    const todoDataComponents = this.state.todos.map(item => {
      return <TodoList key = {item.id} item = {item} handleChange = {this.handleChange} />
    })
    return (
      <div className="todo-list">{todoDataComponents}</div>
    );
  }
}

export default App;

todoList.jsx



class TodoList extends Component {
    constructor(props) {
        super(props);
        this.state = {}
    }
    render() {
        // console.log(this.props)
        return (
            <div className="todo-item">
                <input
                    type="checkbox"
                    checked={this.props.item.completed}
                    onChange = {() => this.props.handleChange(this.props.item.id)}
                />
                <p>{this.props.item.text}</p>
            </div>
        );
    }
}

export default TodoList;

todoData.js

const TodosData = [
    { id: 1, text: "Coding", completed: true },
    { id: 2, text: "Exercise", completed: false },
    { id: 3, text: "Learning", completed: true },
    { id: 4, text: "Programming", completed: true },
    { id: 5, text: "inspire", completed: false },
    { id: 6, text: "motivation", completed: true }
];

export default TodosData;

标签: javascriptarraysreactjs

解决方案


我在您的方法中看不到任何错误handleChange(),它应该可以正常工作。但是,我刚刚更新了您可以在下面测试的一些代码。

我改变了你的名字,TodoList因为它不是一个真正的列表,而是一个项目。我还将它更改为功能组件,因为它只是展示性的,不需要拥有自己的状态。而不是在 之后添加p标签input,您应该使用 alabel使其可访问。

我并没有真正改变你的handleChange()方法中的任何东西,只是删除了console.logs 并且它按预期工作。

更新:您正在使用React.StrictMode,其中 React 在 dev 上渲染所有内容两次。当您handleChange()运行两次时,它会将单击的待办事项的completed状态设置两次,使其恢复到原始状态。因此,如果它false在第一次渲染时设置为true单击,但它会再次渲染,在第二次渲染时又回到false. 你不会注意到它,因为它非常快。

为了避免它,你需要避免改变任何东西。所以我更新了你的onChange处理程序,如果completed属性发生变化,它会返回一个新对象。

随意运行下面的代码片段并单击复选框或项目文本。

const TodosData = [
  { id: 1, text: 'Coding', completed: true },
  { id: 2, text: 'Exercise', completed: false },
  { id: 3, text: 'Learning', completed: true },
  { id: 4, text: 'Programming', completed: true },
  { id: 5, text: 'Inspire', completed: false },
  { id: 6, text: 'Motivation', completed: true },
];

function TodoItem(props) {
  const { handleChange, item } = props;

  return (
    <div className="todo-item">
      <input
        type="checkbox"
        id={`item-${item.id}`}
        checked={item.completed}
        onChange={() => handleChange(item.id)}
      />
      <label htmlFor={`item-${item.id}`}>{item.text}</label>
    </div>
  );
}

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

  handleChange(id) {
    this.setState((prevState) => {
      const updatedTodo = prevState.todos.map((todo) => {
        return todo.id === id ? {
          ...todo,
          completed: !todo.completed,
        } : todo;
      });

      return {
        todos: updatedTodo,
      };
    });
  }

  render() {
    const { todos } = this.state;

    return (
      <div className="todo-list">
        {todos.map((item) => (
          <TodoItem
            key={item.id}
            item={item}
            handleChange={this.handleChange}
          />
        ))}
      </div>
    );
  }
}

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>, 
  document.getElementById('root')
);
body {
  font-family: sans-serif;
  line-height: 1.6;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>


推荐阅读