反应待办事项列表,如何让此删除按钮生效?

时间:2017-11-21 21:19:14

标签: javascript reactjs

我有一个简单易用的应用程序,除了能够从列表中删除项目外,工作正常。我已经为每个列表项添加了按钮。我知道我想使用.filter()方法向状态传递一个没有删除待办事项的新数组,但我不知道如何做这样的事情。

这是App的主要组成部分:

class App extends Component {
  constructor(props){
    super(props);
    this.state = {
      todos: [
        { description: 'Walk the cat', isCompleted: true },
        { description: 'Throw the dishes away', isCompleted: false },
        { description: 'Buy new dishes', isCompleted: false }
      ],
      newTodoDescription: ''
    };
  }

  deleteTodo(e) {
    this.setState({ })
  }

  handleChange(e) {
    this.setState({ newTodoDescription: e.target.value })
  }

  handleSubmit(e) {
    e.preventDefault();
    if (!this.state.newTodoDescription) { return }
    const newTodo = { description: this.state.newTodoDescription, 
    isCompleted: false };
    this.setState({ todos: [...this.state.todos, newTodo], 
    newTodoDescription: '' });
  }

  toggleComplete(index) {
    const todos = this.state.todos.slice();
    const todo = todos[index];
    todo.isCompleted = todo.isCompleted ? false : true;
    this.setState({ todos: todos });
  }

  render() {
    return (
      <div className="App">
        <ul>
          { this.state.todos.map( (todo, index) =>
            <ToDo key={ index } description={ todo.description } 
              isCompleted={ todo.isCompleted } toggleComplete={ () => 
              this.toggleComplete(index) } />
          )}
        </ul>
        <form onSubmit={ (e) => this.handleSubmit(e) }>
          <input type="text" value={ this.state.newTodoDescription } 
            onChange={ (e) => this.handleChange(e) } />
          <input type="submit" />
        </form>

      </div>
    );
  }
}

然后这是To-Do的组件:

class ToDo extends Component {
  render() {
    return (
      <li>
        <input type="checkbox" checked={ this.props.isCompleted } 
          onChange={ this.props.toggleComplete } />
        <button>Destroy!</button>
        <span>{ this.props.description }</span>
      </li>
    );
  }
}

2 个答案:

答案 0 :(得分:1)

在进一步说明之前,不要使用列表索引作为React Elements的键。给你的ToDo一个id并用它作为关键。有时你可以逃避这一点,但是当你删除它时,它几乎总会引起问题。

https://medium.com/@robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318

如果您不想阅读该文章,请了解此

  

让我解释一下,关键是React用来识别DOM的唯一方法   元素。如果您将项目推送到列表或删除会发生什么   中间的东西?如果密钥与React假设之前相同   DOM元素表示与以前相同的组件。但那   不再是真的。

另一方面,在你的按钮上添加一个onClick,并传递你希望它作为App中的道具运行的功能。

<button onClick={() => this.props.handleClick(this.props.id)} />

和App.js

...

constructor(props) {
  ...
  this.handleClick = this.handleClick.bind(this);
}

handleClick(id) {
  // Do stuff
}

<ToDo
  ...
  handleClick={this.handleClick}
/>

答案 1 :(得分:1)

Event handlers救援:

您可以向onDelete发送ToDo道具:

const Todo = ({ description, id, isCompleted, toggleComplete, onDelete }) => 
  <li>
    <input
      type="checkbox"
      checked={isCompleted} 
      onChange={toggleComplete}
    />
    <button onClick={() => onDelete(id)}>Destroy!</button>
    <span>{description}</span>
  </li>

来自App

<ToDo 
  // other props here
  onDelete={this.deleteTodo}
/>

正如@Dakota指出的那样,在通过列表进行映射时使用索引作为键并不是一个好的模式。

也许只需更改您的initialState并为其中的每一个设置id

this.state = {
  todos: [
    { id: 1, description: 'Walk the cat', isCompleted: true },
    { id: 2, description: 'Throw the dishes away', isCompleted: false },
    { id: 3, description: 'Buy new dishes', isCompleted: false }
  ],
  newTodoDescription: '',
}

这也使得从数组中删除项目变得更容易:

deleteTodo(id) {
  this.setState((prevState) => ({
    items: prevState.items.filter(item => item.id !== id),
  }))
}