ReactJS中删除一个项目

8

我是一名新手,正在学习React,并编写了一个能够保存搜索内容的应用程序。当前该程序从静态数组 data 中获取JSON数据。但我无法成功删除搜索列表中的某个搜索记录。

以下是jsbin链接:http://jsbin.com/nobiqi/edit?js,output

这是我的删除按钮元素:

var DeleteSearch = React.createClass({
  render: function() {
    return (
      <button onClick="this.props.deleteSearchItem" value={index}><i className="fa fa-times"></i>
        </button>
    );
  }
});

和我的功能
  deleteSearchItem: function(e) {
    var searchItemIndex = parseInt(e.target.value, 10);
    console.log('remove task: %d', searchItemIndex);
    this.setState(state => {
        state.data.splice(searchItemIndex, 1);
        return { data: state.data };
    });
  }

我已经尝试了一些教程,但是不确定下一步该怎么做。如何删除搜索项?


3
“onClick="this.props.deleteSearchItem"”看起来不对。表达式应该放在花括号中,就像您在“value={index}”中所做的那样。 - elclanrs
onClick={this.props.deleteSearchItem} 这样的语法对我来说很有帮助,因为我是新手。 - Virge Assault
4
请花费半小时前往http://facebook.github.io/react/docs/tutorial.html并浏览整个教程。不要跳过任何部分,遵循指示从头到尾完成。无论您是刚刚开始学习网络开发还是已经有十年以上的经验,该教程都非常出色,可以教授您基础知识,使您不再需要问此类问题。 - Mike 'Pomax' Kamermans
1
你是读了还是实际操作了呢?仅仅阅读教程是不够的。如果你按照教程进行操作,你应该也会学习到如何引用组件函数来处理事件,包括 http://facebook.github.io/react/docs/tutorial.html#controlled-components 部分的内容。 - Mike 'Pomax' Kamermans
下面@the-reason的回答是错误的,因为它直接修改了状态。尽管这个问题之前已经被问答过了,但请仔细阅读... 接受的答案也不正确:https://dev59.com/IVwY5IYBdhLWcg3wM1fK#42711673 - Vince
显示剩余3条评论
3个回答

26

让我猜猜,你是在寻找类似这样的东西吗?

class Example extends React.Component {
    constructor(){
    this.state = {
      data: [
        {id:1, name: 'Hello'},
        {id:2, name: 'World'},
        {id:3, name: 'How'},
        {id:4, name: 'Are'},
        {id:5, name: 'You'},
        {id:6, name: '?'}
      ]
    }
  }

  // shorter & readable 
  delete(item){
    const data = this.state.data.filter(i => i.id !== item.id)
    this.setState({data})
  }

  // or this way, it works as well
  //delete(item){
  //  const newState = this.state.data.slice();
  //    if (newState.indexOf(item) > -1) {
  //    newState.splice(newState.indexOf(item), 1);
  //    this.setState({data: newState})
  //  }
  //}

  render(){
    const listItem = this.state.data.map((item)=>{
        return <div key={item.id}>
        <span>{item.name}</span> <button onClick={this.delete.bind(this, item)}>Delete</button>
      </div>
    })
    return <div>
        {listItem}
    </div>
  }
}

React.render(<Example />, document.getElementById('container'));
在这个例子中,请注意我如何绑定 delete 方法并传递新参数。 fiddle 希望对你有所帮助。
谢谢。

我怀疑这对于长列表来说并不是非常高效的...我的猜测是在列表项中将ID存储为字符串,然后检索它会更高效,也许在React中有一种更“本地”的方法来做到这一点? - Alexander Mills
@AlexMills 在这种情况下,你应该看一下Flux或Redux架构。 - The Reason
2
const newState = this.state.data; 不会复制状态中的数据对象。它只是将对 this.state.data 的引用存储在 newState 中。因此,当您从中删除一个项目时,您直接修改了 this.state.data。这是错误的方式。我通过在您fiddle的分支中注释掉setState行来简单地证明它。至于正确的方法,我不知道...这就是我来这里寻找答案的原因。 - Vince
1
@Vince,没错。我应该使用这些选项之一 Array.prototype.slicespread 运算符来复制新的 state - The Reason

4

楼主这里。因为我现在对React的了解更多,而且这篇文章还有人查看,所以我想用我现在的知识更新一下。

SavedSearches.js

import React from 'react'
import { SearchList } from './SearchList'

let data = [
    {index: 0, name: "a string", url: 'test.com/?search=string'},
    {index: 1, name: "a name", url: 'test.com/?search=name'},
    {index: 2, name: "return all", url: 'test.com/?search=all'}
  ];

let startingIndex = data.length;

export class SavedSearches extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            name: '',
            url: '',
            index: startingIndex,
            data: data
        }
        this.deleteSearch=this.deleteSearch.bind(this)
    }
    deleteSearch(deleteThis) {
        console.log(deleteThis);
        let newData = this.state.data.filter( searchItem => searchItem.index !== deleteThis.index )
        this.setState({
            data: newData
        })
    }

    render() {
        return (
            <div className="search-container">
                <SearchList data={this.state.data} onDelete={this.deleteSearch}/>
            </div>
        )
    }
}

这里我创建了一个名为deleteSearch的方法,它以一个对象作为参数。然后在this.state.data数组上运行.filter,创建一个新数组,包含不符合条件的所有项。条件检查数据数组中每个对象的id是否与参数的id匹配。如果是,则该对象将被删除。由.filter创建的新数组设置为一个名为newData的变量,然后使用newData数组更新状态。

然后我将这个方法通过一个名为onDelete的prop传递给SearchList组件。

在构造函数中,还使用.bind()绑定了这个方法,以便在方法传递到组件树时,this将引用正确的this

SearchList.js

import React from 'react'
import { SearchItem } from './SearchItem'
export class SearchList extends React.Component {
    render() {
      let searchItems = this.props.data.map((item, i) => {
        return (
          <SearchItem index={i} searchItem={item} url={item.url} onDelete={this.props.onDelete}>
            {item.name}
          </SearchItem>
        );
      });
      return (
        <ul>
          {searchItems}
        </ul>
      );
    }
}

我的deleteSearch方法只是在这里通过组件树传递。 SearchList以props的形式接收该方法this.props.onDelete并将其传递给SearchItem

另一个主要关键点是map函数中的参数被作为props传递:searchItem={item}。 这将允许通过props访问整个当前对象;如果您记得,我的deleteSearch函数以对象作为参数。

SearchItem.js

import React from 'react'

export class SearchItem extends React.Component {
    constructor(props) {
        super(props);
        this.handleDelete=this.handleDelete.bind(this)
    }
    handleDelete() {
        this.props.onDelete(this.props.searchItem)
    }
    render() {
      return (
        <li key={this.props.index}> {/* Still getting a console error over this key */}
          <a href={this.props.url} title={this.props.name}>
            {this.props.children}
          </a>
          &nbsp;({this.props.url})
          <button onClick={this.handleDelete} value={this.props.index}><i className="fa fa-times"></i>
          </button>
        </li>
      );
    }
  };

现在我的方法到达了它将要被使用的地方。我创建一个处理程序方法handleDelete,在其中使用this.props.onDelete访问deleteSearch方法。然后,我使用this.props.searchItem向它传递正在单击的列表项的对象。
为了使用户单击时这个方法能够起作用,我必须添加一个调用我的处理程序方法的onClick事件监听器,如下所示:onClick={this.handleDelete}。最后一步是在SearchItem构造函数方法中绑定this.handleDelete
现在,单击按钮将从this.state.data数组中删除该项。有关如何向数组中添加项的示例,请参见我的存储库

0
你是否在寻找类似这样的东西?

Todos.js

import React from 'react'
import {TodoItem} from "./TodoItem";

export const Todos = (props) => {

    let myStyle = {
        minHeight: "70vh",
        margin: "40px auto"
    }
    return (
        <div className="container" style={myStyle}>
            <h3 className="my-3">List</h3>
            {props.todos.length===0? "No records to display":  
            props.todos.map((todo)=>{
                console.log(todo.sno);
                return (<TodoItem todo={todo} key={todo.sno} onDelete={props.onDelete}/>   
                )
            })
              } 
        </div>
    )
}

TodoItem.js

import React from 'react'

export const TodoItem = ({todo, onDelete}) => {

    return (
        <>
        <div>
           <h4>{todo.title}</h4>
           <p>{todo.desc}</p>
           <button className="btn btn-sm btn-danger" onClick={()=>{onDelete(todo)}}>Delete</button> 
        </div>
        <hr/> 
        </>
    )
}

请查看代码库,在这里您可以找到添加、删除和列出项目。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接