简体   繁体   中英

removing an index from an array of objects in react.js always removes the last index

I'm having an issue with removing an index from an array of objects in react.js.

I have a table which displays the name and value of the data from the state. Each row will have a button to delete it and it works.

There's another button which pushes a new object of an HTML input in the array so the user can add new values. The problem I have here is with the delete button. If I add 2 or 3 rows then the delete button always removes the last row.

I'm not sure why the delete button doesn't work.

I appreciate it if anyone can help.

Here is the code:

class App extends Component {
  constructor(props) {
  super(props);
  this.state = {
    datas: [
      { name: 'test', value: 'test' },
      { name: 'test 1', value: 'test 1' }
    ]
  }
}

delete = (index) => {
  let datas = this.state.datas.filter((e, i) => i !== index);
  this.setState({ datas : datas });
}

addnew = () => {
  let datas = this.state.datas;
  datas.push( {name: <input />, value: <input /> })
  this.setState({ datas : datas });
}

render() {
  return (
    <div>
      <button onClick={this.addnew}>Add</button>
      <table>
        <thead>
          <tr>
            <th>Name</th>
            <th>Value</th>
            <th>Action</th>
          </tr>
        </thead>
        <tbody>
          {this.state.datas.map((data, index) => (
            <tr key={index}>
              <th>{data.name}</th>
              <th>{data.value}</th>
              <th><button onClick={() => this.delete(index)}>delete</button>                  </th>
          </tr>
         ))}
        </tbody>
      </table>
    </div>
  );
}}
export default App;

When adding row you set initial values as input elements. Than when removing you are looking in array index of object containing input elements. Function indexOf returns first index of occurrence.

Better solution is to update delete button to pass index of element to delete

            <th><button onClick={() => this.delete(index)}

Than just remove element with given index in your function.

delete = (index) => {
    let datas = this.state.datas.filter((e, i) => i !== index);
    this.setState({ datas : datas });
  }

But that still won't fully fix your solution because you are setting new array element to hold input elements. Which you shouldn't.

The problem, I believe, is in using map's index as key. You can have an index property in each item itself.

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      datas: [
        { index:0, name: "test", value: "test" },
        { index:1, name: "test 1", value: "test 1" },
        { index:2,  name: "test 2", value: "test 2" }
      ],
      counter: 3
    };
  }

  delete = index => {
    let datas = this.state.datas.filter((e, i) => i !== index);
    this.setState({ datas: datas });
  };

  addnew = () => {
    let datas = this.state.datas;
    datas.push({ index: this.state.counter, name: <input />, value: <input /> });
    this.setState({ datas: datas, counter: this.state.counter + 1 });
  };

  render() {
    return (
      <div>
        <button onClick={this.addnew}>Add</button>
        <table>
          <thead>
            <tr>
              <th>Name</th>
              <th>Value</th>
              <th>Action</th>
            </tr>
          </thead>
          <tbody>
            {this.state.datas.map((data, index) => (
              <tr key={data.index}>
                <th>{data.name}</th>
                <th>{data.value}</th>
                <th>
                  <button onClick={() => this.delete(index)}>delete</button>{" "}
                </th>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    );
  }
}

Edit on CodeSandbox: https://codesandbox.io/embed/p57now4pjx?fontsize=14

A simple solution is to set the unique key on the component. For that try break your table into different components such as <Row /> and <Col /> and then set a unique key on those components, like: <Row key={"uniqKey1"} onClick={() => this.delete(index) />

Then it will definitely remove that component.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM