【问题标题】:React: deleting a targeted table row always deletes the first rowReact:删除目标表行总是删除第一行
【发布时间】:2019-04-04 07:06:27
【问题描述】:

我有一个组件,它根据在搜索框中输入的字词过滤公司,然后根据他们的帐户是否已激活再次过滤它们,然后将它们映射到一个包含几列公司数据的表中.每个公司的最后一个表列包含几个按钮,其中一个是触发模态对话框的删除按钮,然后必须从模态中确认或取消删除。

为简洁起见,我将省略不重要的导入和导出:

import {searchingFor} from '../../../containers/CompaniesContainer/CompaniesContainer';
const companiesTable = (props) => {
  return (
    <table className={classes.Table}>
      <thead>
        <tr>
          <th className={classes.First}>&nbsp;</th>
          <th onClick={props.sortByName} className={[classes.Second, props.sortingClass].join(' ')}><span>Name</span><img src={downArrow} alt="down-arrow" /></th>
          <th onClick={props.sortByAddress} className={[classes.Third, props.sortingClass].join(' ')}><span>Email address</span><img src={downArrow} alt="down-arrow" /></th>
          <th onClick={props.sortByAdded} className={[classes.Fourth, props.sortingClass].join(' ')}><span>Added</span><img src={downArrow} alt="down-arrow" /></th>
          <th className={classes.Last}>&nbsp;</th>
        </tr>
      </thead>
      <tbody>
        {
          props.companies.filter(searchingFor(props.term)).filter(function (company) {
            if(props.isActive === true) {
              return company.active;
            } else {
              return !company.active
            }
          }).map((item, index) =>
            <tr key={item.id}>
              <td>
                <img src={companyImg} alt="companies" />
              </td>
              <td>{item.name}</td>
              <td>{item.street},<br/>{item.city}</td>
              <td>{item.added}</td>
              <td>
                <Button btnType={props.btnClass1} onClick={() => props.deleteInitiate(item.name)}>{props.btnText1}</Button>
                <Button btnType={props.btnClass2}>{props.btnText2}</Button>
                <Button btnType={props.btnClass3}>{props.btnText3}</Button>
              </td>
            </tr>
          )
        }
      </tbody>
    </table>
  );
};

export default companiesTable;

然后从包含两个选项卡的组件安装此组件两次。在一个选项卡中,我列出了活动帐户,而在另一个选项卡中列出了非活动帐户。

const companiesTabs = (props) => {
  return (
    <Tabs tabsClass={classes.TabList} tabContentClass={classes.TabContent}>
      <div 
        label="Active"
        tabClass={classes.TabItem} 
        activeClass={classes.TabItemActive} 
        hasLabel={true}
        hasImg={false}  
      >
        <CompaniesTable 
          isActive={true} 
          term={props.term}
          companies={props.companies}
          sortByName={props.sortByName}
          sortByAddress={props.sortByAddress}
          sortByAdded={props.sortByAdded}
          sortingClass={props.sortingClass}
          toggleSortingClass={props.toggleSortingClass}
          btnClass1="secondary"
          btnClass2="primary"
          btnClass3="success"
          btnText1="Delete"
          btnText2="Deactivate"
          btnText3="Sign in"
          deleteInitiate={props.deleteInitiate}
        />
      </div>
      <div 
        label="Inactive"
        tabClass={classes.TabItem} 
        activeClass={classes.TabItemActive}
        hasLabel={true}
        hasImg={false}
      >
        <CompaniesTable 
          isActive={false} 
          term={props.term}
          companies={props.companies}
          sortByName={props.sortByName}
          sortByAddress={props.sortByAddress}
          sortByAdded={props.sortByAdded}
          sortingClass={props.sortingClass}
          toggleSortingClass={props.toggleSortingClass}
          btnClass1="secondary"
          btnClass2="activate"
          btnClass3="success"
          btnText1="Delete"
          btnText2="Activate"
          btnText3="Sign in"
          deleteInitiate={props.deleteInitiate}
        />
      </div>
    </Tabs>
  );
};

export default companiesTabs;

然后我有一个包含选项卡组件的组件:

const companies = (props) => {
  return (
    <React.Fragment>
      <CompaniesTabs
        term={props.term}
        companies={props.companies}
        sortByName={props.sortByName}
        sortByAddress={props.sortByAddress}
        sortByAdded={props.sortByAdded}
        sortingClass={props.sortingClass}
        toggleSortingClass={props.toggleSortingClass}
        deleteInitiate={props.deleteInitiate}
      />
    </React.Fragment>
  );
};

还有一个基于类的容器组件,它包含状态和方法,并呈现ModalSearchBoxCompanies 组件。

export function searchingFor(term) {
  return function(x) {
    return x.name.toLowerCase().includes(term.toLowerCase()) || !term;
  }
}

class CompaniesContainer extends Component {
  constructor(props) {
    super(props);
    this.state = {
      term: '',
      sorting: false,
      deleting: false,
      deletingCompanyName: null,
      companies: [
        { 
          id: 1,
          name: "Company 1",
          street: "123 Some Street",
          city: "London",
          added: "03.04.19",
          active: true,
        },
        { 
          id: 2,
          name: "Company 2",
          street: "321 Some other Street",
          city: "New York",
          added: "04.04.19",
          active: false,
        }
      ]
    }
    this.compareBy.bind(this);
    this.sortBy.bind(this);
    this.toggleSortingClass= this.toggleSortingClass.bind(this);
    this.searchHandler = this.searchHandler.bind(this);
    this.deleteInitiateHandler = this.deleteInitiateHandler.bind(this);
  }

  compareBy(key) {
    return function (a, b) {
      if (a[key] < b[key]) return -1;
      if (a[key] > b[key]) return 1;
      return 0;
    };
  }

  sortBy(key) {
    let arrayCopy = [...this.state.companies];
    arrayCopy.sort(this.compareBy(key));
    this.setState({companies: arrayCopy});
  }

  toggleSortingClass() {

  };

  searchHandler(event){
    this.setState({term: event.target.value});
  }

  deleteInitiateHandler = (name) => {
    this.setState({deleting: true, deletingCompanyName: name});
  }

  deleteHandler = (companyIndex) => {
    const companies = [...this.state.companies];
    companies.splice(companyIndex, 1);
    this.setState({companies: companies, deleting: false});
  };

  deleteCancelHandler = () => {
    this.setState({deleting: false});
  }

  render() { 
    const {term, companies} = this.state;

    return (
      <React.Fragment>
        <Modal 
          show={this.state.deleting} 
          modalClosed={this.deleteCancelHandler} 
        >
          <DeleteCompany 
            delete={this.deleteHandler} 
            deleteCancel={this.deleteCancelHandler}
          />
        </Modal>
        <SearchBox 
          change={this.searchHandler} 
          value={term} 
          placeholder="Search Companies…" 
        />       
        <Companies 
          term={term}
          companies={companies}
          sortByName={() => this.sortBy('name')}
          sortByAddress={() => this.sortBy('city')}
          sortByAdded={() => this.sortBy('id')}
          sortingClass={this.state.sorting}
          toggleSortingClass={this.toggleSortingClass}
          deleteInitiate={this.deleteInitiateHandler}
        />             
      </React.Fragment>
    );
  }
};
export default CompaniesContainer;

最后,一个DeleteCompany 组件被挂载到一个Modal 组件中,其中包含取消和删除按钮:

const deleteCompany = (props) => {
  return (
    <React.Fragment>
      <h3 className={classes.ModalTitle}>Confirm deletion</h3>
      <p className={classes.ModalText}>Are you sure you want to delete the company of <strong>{props.name}</strong></p>
      <ul className={classes.ModalButtonsList}>
        <li className={classes.ModalButtonsListItem}>
          <Button btnType='primary' onClick={props.deleteCancel}>Cancel</Button>
        </li>
        <li className={classes.ModalButtonsListItem}>
          <Button btnType='danger' onClick={props.delete}>Delete</Button>
        </li>
      </ul>
    </React.Fragment>
  );
};

我的问题是,当我单击特定公司行的删除按钮并通过单击模式内的删除按钮确认删除该行时,删除了错误的行。出于某种原因,无论我要删除哪一行,它总是删除第一个表行。有人可以帮我弄清楚为什么会这样吗?

【问题讨论】:

    标签: reactjs


    【解决方案1】:

    这是因为从DeleteCompany 组件中,您没有在delete 方法中传递任何索引(在 CompaniesContainer 中定义为 deleteHandler),这里:

    <Button btnType='danger' onClick={props.delete}>Delete</Button>
    

    所以,您似乎在做类似:[1,2,3].splice(undefined, 1),这将始终删除第一个元素。

    示例

    var a = [1,2,3,4];
    
    a.splice(undefined, 1);
    
    console.log('a', a);

    解决方案是,您在单击删除按钮时将公司名称从companyTable 组件传递给CompaniesContainer,因此请使用该名称而不是索引来删除公司。

    像这样:

    deleteHandler = (companyIndex) => {
      this.setState(prevState => ({
        companies: prevState.companies.filter(el => el.name != prevState.deletingCompanyName)
      }))
    };
    

    注意:如果公司名称不是唯一的,请在此处传递来自companiesTable 的任何唯一值而不是名称:

    <Button btnType={props.btnClass1} onClick={() => props.deleteInitiate(item.id)}>{props.btnText1}</Button>
    

    并使用该 ID 删除公司。

    【讨论】:

    • 我不得不将 'el => el.name == prevState.deletingCompanyName' 更改为 'el => el.name !== prevState.deletingCompanyName',但它可以工作。谢谢。
    • 我会尝试传递 id 而不是公司名称。
    猜你喜欢
    • 2021-08-13
    • 2017-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多