将 onClick 功能添加到 React 待办事项列表

Jev*_*ran 1 javascript arrays onclick reactjs

我用 React 创建了一个待办事项列表。我希望能够通过单击它们来标记已完成的任务。我还希望能够通过单击按钮清除已完成的任务。这两个函数在我设置的代码中无法正常工作。当我单击单个待办事项以将其标记为完成时,列表中的每个待办事项都会被标记为已完成,因此会显示一个“行通过”。当我然后单击指定的按钮清除已完成的任务时,绝对没有任何反应。有人可以帮我解决这两个问题吗?

来自 App 组件的代码:

class App extends React.Component {
  constructor() {
    super();
    this.state = {
      todos: [
        {
          task: "learn how to fly drone",
          id: Date.now(),
          completed: false
        }, 
        {
          task: "learn React class components",
          id: Date.now(),
          completed: false
        },
        {
          task: "practice editing videos",
          id: Date.now(),
          completed: false
        },
        {
          task: "read Ten Years A Nomad",
          id: Date.now(),
          completed: false
        }
    ],
      todo: ''
    }
  }

  inputChangeHandler = event => {
    this.setState({[event.target.name]: event.target.value})
  }

  addTask = event => {
    event.preventDefault();
    let newTask = {
      task: this.state.todo,
      id: Date.now(),
      completed: false
    };
    this.setState({
      todos: [...this.state.todos, newTask],
      todo: ''
    })
  }

  toggleComplete = itemId => {
    const todos = this.state.todos.map(todo => {
      if (todo.id === itemId) {
        todo.completed = !todo.completed
      }
      return todo
    });
    this.setState({todos, todo: ''})
  }

  clearCompleted = e => {
    e.preventDefault();
    return this.state.todos.filter(item => !item.completed)
  }

  render() {
    return (
      <div className="App">
        <h2>Welcome to your Todo App!</h2>
        <TodoList 
          todos={this.state.todos} 
          toggleComplete={this.toggleComplete} />
        <TodoForm todos={this.state.todos} value={this.state.todo} inputChangeHandler={this.inputChangeHandler} addTask={this.addTask} clearCompleted={this.clearCompleted}/>
      </div>
    );
  }
}

export default App;
Run Code Online (Sandbox Code Playgroud)

待办事项列表:

const TodoList = props => {
    return (
        <div>
            {props.todos.map((todo, id) => (
                <Todo 
                    todo={todo} 
                    key={id} 
                    toggleComplete={props.toggleComplete} />
            ))}
        </div>
    )
}

export default TodoList;
Run Code Online (Sandbox Code Playgroud)

去做:

const Todo = props => {
    return (
        <div 
            key={props.todo.id}
            onClick={() => {
                props.toggleComplete(props.todo.id)
            }}>
            <p 
                style={{textDecoration: props.todo.completed ? 'line-through' : 'none'}}>
                {props.todo.task}
            </p>
        </div>
    )
}

export default Todo;
Run Code Online (Sandbox Code Playgroud)

TodoForm:

const TodoForm = props => {
    return (
        <form>
            <input 
                name="todo" 
                value={props.value} 
                type="text" 
                onChange={props.inputChangeHandler} 
                placeholder="Enter new task" />
            <button onClick={props.addTask}>Add Todo</button>
            <button onClick={props.clearCompleted}>Clear Completed</button>
        </form>
    )
}

export default TodoForm;
Run Code Online (Sandbox Code Playgroud)

wen*_*jun 5

1)之所以每一项都被标记,是因为todos状态内的所有对象都有相同的id。因此,toggleComplete()最终会将其中的所有对象标记todostrue.

您可以做的是为每个对象分配一个唯一的id,而不是为所有对象分配id相同的Date对象对象。

下面是一个例子:

constructor() {
  super();
  this.state = {
    todos: [
      {
        task: "learn how to fly drone",
        id: 1,
        completed: false
      }, 
      {
        task: "learn React class components",
        id: 2,
        completed: false
      },
      {
        task: "practice editing videos",
        id: 3,
        completed: false
      },
      {
        task: "read Ten Years A Nomad",
        id: 4,
        completed: false
      }
  ],  
    todo: ''
  }
}
Run Code Online (Sandbox Code Playgroud)

2) 接下来,clearCompleted不是调用setState(),因此,没有任何任务被清除。我假设你试图设置completed为假?在这种情况下,您可以简单地false为所有对象设置完成,然后更新您的状态。

clearCompleted = e => {
  e.preventDefault();
  const todos = this.state.todos.map(todo => ({
    ...todo,
    completed: false,
  }));

  this.setState({
    todos,
  });
}
Run Code Online (Sandbox Code Playgroud)

我创建了一个演示来解决您的问题。