首页 > 解决方案 > 如何在反应中将句柄更改添加到待办事项应用程序?

问题描述

我是新来的反应和制作待办事项应用程序。

我添加了一个事件侦听器(handleChange)来将 todosData.completed 从 true 翻转为 false,反之亦然,从而允许用户选中和取消选中复选框。

我该如何纠正这一点。这是我的代码:

 class App extends React.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>{todoItems}</div>
    );
  }
}

export default App;

function TodoItem(props) {
  return (
    <div>
      <input 
        type = 'checkbox' checked = {props.item.completed}
        onChange = {() => props.handleChange(props.item.id)} />
      <p> {props.item.task} </p>
    </div>
  );
}

export default TodoItem;

有人能告诉我我错过了什么吗?

标签: javascriptreactjs

解决方案


正如@ChrisG 在评论中指出的那样,当您的组件被包裹在<React.StrictMode>. 如果您使用 Create React App 创建了您的应用程序,默认情况下会这样做,请检查您的index.js文件。

StrictMode 是一项开发功能,可迫使您编写更好的代码。它只影响您的开发构建,因此如果在生产模式下构建和运行,您的代码应该可以工作。

StrictMode 所做的一件事就是运行你的setState方法两次,以确保你不依赖它只运行一次。因此,第一次运行时,您按预期反转 todo.completed,第二次将其恢复为原始值。

这告诉您的是,您的handleChange函数实际上是在使用非纯方法更新状态,因为您实际上更改todoprevState.todos.map.

相反,您需要做的是返回一个新todo对象,该对象将是另一个对象的副本,仅completed修改了属性,如下所示:

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

    return {
     todos: updatedTodos
    };
  });
}

或者使用ES6 扩展运算符,如下所示:

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

我相信这是一个比 Chris G 建议删除 <React.StrictMode> 更好的解决方案,因为 StrictMode 实际上可以帮助您编写更好的代码。


推荐阅读