简体   繁体   English

在 React todo 应用程序中单击时复选框不会更改其值

[英]Checkbox doesn't change its value on click in React todo application

Please help me with this I don't understand exactly where I doing wrong.请帮我解决这个问题,我不明白我做错了什么。 So when I click on the checkbox values are not changing(if it's by default true when I click on the click it should the false ).因此,当我单击复选框时,值不会更改(如果在单击单击时默认为true ,则它应该为false )。 For that in onChange in todoList component I am calling handleClick function there I change the todo.completed value(basically toggling the values).为此,在todoList组件的onChange中,我正在调用handleClick函数,在那里我更改了todo.completed值(基本上是切换值)。

In App.js inside the handleClick method When do console.log(todo) before returning from the map function value is toggling fine, but it is not updated in the updatedTodo .App.jshandleClick方法中,当从 map 函数返回值之前执行console.log(todo)切换正常,但它没有在updatedTodo更新。

App.js应用程序.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待办事项列表.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 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;

I can't see any error in your handleChange() method, it should work fine.我在您的handleChange()方法handleChange()不到任何错误,它应该可以正常工作。 However, I've just updated some of your code which you can test below.但是,我刚刚更新了您的一些代码,您可以在下面进行测试。

I changed the name of your TodoList as it's not really a list but an item.我更改了您的TodoList的名称,因为它实际上不是一个列表而是一个项目。 I also changed it to a functional component as it's only presentational, there is no need to have its own state.我还把它改成了一个功能组件,因为它只是展示性的,不需要有自己的状态。 Instead of adding a p tag after the input , you should use a label to make it accessible.与其在input之后添加p标签,不如使用label使其可访问。

I haven't really changed anything inside your handleChange() method, only removed the console.log s and it works as expected.我并没有真正更改您的handleChange()方法中的任何内容,只是删除了console.log并且它按预期工作。

Update : You're using React.StrictMode , where React renders everything twice on dev.更新:您正在使用React.StrictMode ,其中 React 在开发中渲染所有内容两次。 As your handleChange() runs twice, it sets the clicked todo's completed state twice, making it to set back to its original state.当您的handleChange()运行两次时,它会两次设置被点击的待办事项的completed状态,使其设置回其原始状态。 So if it's false on first render it sets to true on click, but it's rendered again and on the second one it's back to false .所以,如果这是false的第一渲染其设置为true的点击,但它再次呈现和第二个它的回false You won't notice it as it's pretty fast.你不会注意到它,因为它非常快。

To avoid it, you need to avoid mutating anything.为了避免它,你需要避免改变任何东西。 So I've updated your onChange handler, it returns a new object if the completed property is changed.所以我更新了你的onChange处理程序,如果已completed属性发生更改,它会返回一个新对象。

Feel free to run the code snippet below and click on the checkboxes or the item texts.随意运行下面的代码片段并单击复选框或项目文本。

 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>

Instead of using an additional variable, you can do it in one line.您可以在一行中完成,而不是使用额外的变量。 Can u see if this works for you.你能看看这是否适合你。

handleChange(id) {
    this.setState(prevState => prevState.map(todo => todo.id === id ? {...todo, completed: !todo.completed} : todo )
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM