【问题标题】:How to delete a ToDo Item onClick in React?如何在 React 中删除 ToDo 项 onClick?
【发布时间】:2017-06-29 17:52:08
【问题描述】:

我正在用 React 做一个简单的 todo 应用程序,只是为了练习。单击列表项时如何删除它?

这是我的 todos.js

export default class Todos extends Component {
    constructor(props) {
        super(props);
        this.state = { todos: [], text: '' };
    }

    addTodo(e) {
        e.preventDefault();
        this.setState({ todos: [ this.state.text, ...this.state.todos ] });
        this.setState({ text: ''});
    }

    updateValue(e) {
        this.setState({ text: [e.target.value]})
    }

    render() {
        return(
            <div>
                <form onSubmit = {(e) => this.addTodo(e)}>
                    <input
                        placeholder="Add Todo"
                        value={this.state.text}
                        onChange={(e) => {this.updateValue(e)}}
                    />
                    <button type="submit">Add Todo</button>
                </form>
                <TodoList todos={this.state.todos}/>
            </div>
        );
    }
}

这里是 TodoList.js,我试图从中删除一个列表项。

import React, { Component } from 'react';
import { connect } from 'react-redux';

export default class TodoList extends Component {
    removeItem(e) {
        // splice this.props.todos??
    }
    render() {
        return(
            <ul>
                { this.props.todos.map((todo) => {
                    return <li onClick={(e) => { this.removeItem(e)}} key={todo}>{ todo }</li>
                })}
            </ul>
        );
    }
}

【问题讨论】:

  • 只需从具有键的数组中删除对象并使用新对象更新状态。

标签: reactjs


【解决方案1】:

要删除待办事项,首先从父组件传递一个函数:

<TodoList todos={this.state.todos} removeTodo={this.removeTodo}/>

constructor中绑定这个函数:

this.removeTodo = this.removeTodo.bind(this);

在父组件中定义此函数,它将从state变量中删除该项目:

removeTodo(name){
    this.setState({
        todo: this.state.todo.filter(el => el !== name)
    })
}

然后在子组件内部调用这个方法删除todo:

export default class TodoList extends Component {
    removeItem(e) {
        this.props.removeTodo(item);
    }
    render() {
        return(
            <ul>
                { this.props.todos.map((todo) => {
                    return <li onClick={() => { this.removeItem(todo)}} key={todo}>{ todo }</li>
                })}
            </ul>
        );
    }
}

建议:

如果您想设置多个state 值,请不要在function 内多次调用setState,然后这样写:

this.setState({
    a: value1,
    b: value2,
    c: value3
})

工作示例:

class Todos extends React.Component {
    constructor(props) {
        super(props);
        this.state = { todos: [], text: '' };
        this.removeTodo = this.removeTodo.bind(this);
    }

    addTodo(e) {
        e.preventDefault();
        this.setState({ 
        	todos: [ this.state.text, ...this.state.todos ],
        	text: ''
        });
    }

    removeTodo(name, i){
        let todos = this.state.todos.slice();
        todos.splice(i, 1);
        this.setState({
            todos
        });
    }

    updateValue(e) {
        this.setState({ text: e.target.value})
    }

    render() {
        return(
            <div>
                <form onSubmit = {(e) => this.addTodo(e)}>
                    <input
                        placeholder="Add Todo"
                        value={this.state.text}
                        onChange={(e) => {this.updateValue(e)}}
                    />
                    <button type="submit">Add Todo</button>
                </form>
                <TodoList todos={this.state.todos} removeTodo={this.removeTodo}/>
            </div>
        );
    }
}

class TodoList extends React.Component {

    removeItem(item, i) {
        this.props.removeTodo(item, i);
    }

    render() {
        return(
            <ul>
                { this.props.todos.map((todo,i) => {
                    return <li onClick={() => { this.removeItem(todo, i)}} key={i}>{ todo }</li>
                })}
            </ul>
        );
    }
}

ReactDOM.render(<Todos/>, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id='app'/>

更新:

这是@whs.bsmith 的疑问,我建议的代码在用户将在待办事项列表中添加唯一项目的情况下正常工作,如果他尝试添加相同的项目,它将不会反映在 ui 中因为 OP 使用 todo 项目名称作为键,并且键应该是唯一的。

解决这个问题:

在工作 sn-p 中,我使用索引代替待办事项名称作为键,这将正常工作,它将允许用户多次添加相同的项目,并且在删除时,它只会删除该特定项目而不是所有具有相同名称的项目,但使用索引作为键不是一个好主意。

【讨论】:

  • 这不会在所有情况下都有效,因为您可能需要相同的待办事项,并且这种过滤器将始终将它们都删除
  • @whs.bsmith 除非他拥有每个待办事项的 ID 或唯一密钥,否则它将起作用。它将被该唯一键过滤
  • 实际上,在您的示例中,您不能将相同的待办事项放在首位
  • @whs.bsmith 检查更新的答案,它不允许添加相同的项目,因为 OP 使用 todo 的名称作为键,现在通过使用索引我们可以添加多个同名的 todo ,它也会删除特定的项目,但使用 index 作为 key 不是一个好主意。
  • 好的,但我认为你最初是使用 todo 本身进行过滤
【解决方案2】:

您在 addTodo 函数中调用了两次 setState。您可以像这样在单个 setState 函数中设置 todostext

addTodo(e) {
    e.preventDefault();
    this.setState({ todos: [ this.state.text, ...this.state.todos ], text: '' });
}

不要在 TodoList 组件中编写 removeItem 函数,因为它纯粹是在处理道具。将 Todos 中的 removeItem 函数传递给它,然后在 Todos 的 removeItem 函数中删除该项目,如下所示:

import React, {Component} from 'react'
export default class Todos extends Component {
  constructor(props) {
    super(props);
    this.state = { todos: [], text: '' };
    this.removeItem = this.removeItem.bind(this)
  }

  addTodo(e) {
    e.preventDefault();
    this.setState({ todos: [ this.state.text, ...this.state.todos ], text: '' });
  }


  updateValue(e) {
    this.setState({ text: [e.target.value]})
  }
  removeItem(index) {
    const todos = this.state.todos.filter((todo, todoIndex) => {
      return todoIndex !== index
    })
    this.setState({ todos })
  }
  render() {
    return(
      <div>
        <form onSubmit = {(e) => this.addTodo(e)}>
          <input
            placeholder="Add Todo"
            value={this.state.text}
            onChange={(e) => {this.updateValue(e)}}
            />
          <button type="submit">Add Todo</button>
        </form>
        <TodoList todos={this.state.todos} removeItem={this.removeItem} />
      </div>
    );
  }
}

class TodoList extends Component {
  render() {
    return(
      <ul>
        { this.props.todos.map((todo, index) => {
          return <li onClick={(e) => { this.props.removeItem(index)}} key={todo}>{ todo }</li>
        })}
      </ul>
    );
  }
}

希望,它会有所帮助。

【讨论】:

    【解决方案3】:
    class TodoList extend React.Component{
        constructor(props){
            super(props);
            this.state = {
                todos: [],
                todo: ''
            }
            this.changeTodo = this.changeTodo.bind(this);
            this.addTodo = this.addTodo.bind(this);
            this.removeTodo = this.removeTodo.bind(this);
        }
    
        changeTodo(event){
            this.setState({
                todo: event.target.value
            })
        }
    
        addTodo(){
            let { todo, todos } = this.state;
            this.setState({
                todo: '',
                todos: [...todos, todo]
            })
        }
    
        removeTodo(index){
            let { todos } = this.state;
            todos.splice(index, 1);
            this.setState({
                todos: todos
            })
        }
    
        render(){
            let { todo, todos } = this.state;
            return <div>
                <input value={todo} onChange={this.changeTodo}/>
                <button onClick={this.addTodo}>Add Todo</button>
                {
                    todos.map((todo, index)=>{
                        return <h1 onClick={this.removeTodo.bind(undefined, index)} key={index}>{todo}</h1>
                    })
                }
            </div>
        }
    }
    

    这是 TodoList 的一个小例子。浏览此代码以了解您的 TodoList 应用程序中的删除待办事项。

    【讨论】:

      【解决方案4】:

      首先,您希望 removeItem 方法存在于 Todos 类中,因为那是 状态被存储。然后,您可以使用过滤器或切片

      export default class Todos extends Component {
          constructor(props) {
              super(props);
              this.state = { todos: [], text: '' };
          }
      
          addTodo(e) {
              e.preventDefault();
              this.setState({ todos: [ this.state.text, ...this.state.todos ] });
              this.setState({ text: ''});
          }
      
          updateValue(e) {
              this.setState({ text: [e.target.value]})
          }
      
          removeItem = index => {
              //either use filter
              const { todos } = this.state;
              const newTodos = todos.filter((todo, i) => i !== index);
              this.setState({ todos: newTodos});
      
              //or use slice
              const slicedNewTodos = todos.slice(0, index).concat(todos.slice(index + 1));
              this.setState({ todos: slicedNewTodos});
          }
      
          render() {
              return(
                  <div>
                      <form onSubmit = {(e) => this.addTodo(e)}>
                          <input
                              placeholder="Add Todo"
                              value={this.state.text}
                              onChange={(e) => {this.updateValue(e)}}
                          />
                          <button type="submit">Add Todo</button>
                      </form>
                      <TodoList removeItem={this.removeItem} todos={this.state.todos}/>
                  </div>
              );
          }
      }
      
      import React, { Component } from 'react';
      import { connect } from 'react-redux';
      
      class TodoList extends Component {
          render() {
              return(
                  <ul>
                      { this.props.todos.map((todo, index) => {
                          return <li onClick={() => this.props.removeItem(index)} key={todo}>{ todo }</li>
                      })}
                  </ul>
              );
          }
      }
      

      【讨论】:

        【解决方案5】:

        唯一要做的就是将todos移动到TodoList中的state,并将当前待办事项的索引传递给removeItem方法。然后按照你的建议拼接。

        TodoList:

        constructor(props) {
            super(props);
        
            this.state = { todos: props.todos };
        }
        
        removeItem(index) {
            this.setState({
                todos: this.state.todos.filter((_, i) => i !== index)
            });
        }
        
        render() {
            return(
                <ul>
                    { this.state.todos.map((todo, index) => {
                        return <li onClick={(e) => { this.removeItem(index)}} key={todo}>{ todo }</li>
                    })}
                </ul>
            );
        }
        

        删除由Removing element from array in component state提供的项目

        【讨论】:

          【解决方案6】:

          每个人都给出了一个很好的全局概览。 我发现这是从 todolist 中删除 todo 的好方法

          tod​​olist.splice(index, 1);

          Splice 从 index 的 startIndex 中移除 1 个元素(在 todolist 数组中)

          【讨论】:

            【解决方案7】:

            我们可以为待办事项数据设置一个标志,在初始化该数据时,我们可以将该标志设置为真,当我们删除待办事项列表时,我们可以将该标志设置为假。请参考以下代码。

            const TodoComponent = ({ dataArray }) => {
            
              const [todos, setTodos] = useState(dataArray)
            
              // initial loading of todo items.
              useEffect(() =>{
                if (dataArray.length) {
                  dataArray.forEach(todo =>{
                    todo.show = true
                  })
                  setTodos(dataArray)
                }
              }, [dataArray])
            
             // Close the todo Item.
              const closeTodoItem = (todo, index) =>{
                todo.show = false
                todos[index] = todo
                setTodos([...todos])
              }
            
              return (
                todos.filter(todo => todo.show === true).length >0  &&
                (
                  <Col span={24} className={style.todoBg} style={compStyle}>
                    {todos.map((todo,index) => (
                      (todo.show && (
                        <Col span={24} className={style.todo}>
                          <Col className={style.todoInner}>
                            <p> {todo.content} </p>
                          </Col>
                          <Icon onClick={() => closeTodoItem(todo, index)} className={style.close}>close</Icon>
                        </Col>
                      ))
                    ))}
                  </Col>
                )
              )}
            

            上述方法对我有用。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2018-12-02
              • 1970-01-01
              • 2021-01-18
              • 1970-01-01
              • 1970-01-01
              • 2021-02-13
              • 1970-01-01
              相关资源
              最近更新 更多