react dynamic row input value remained after remov

2019-07-29 05:37发布

问题:

I have a problem with below code

export class MultipleInput extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      rowCount: 1
    };
  }
  addRow = () => this.setState({ rowCount: this.state.rowCount + 1 });
  deleteRow = () => this.setState({ rowCount: this.state.rowCount - 1 });
  renderRow = i => {
    const { type, value } = this.props;
    const { rowCount } = this.state;
    return (
      <div>
        <input type={type} value={value} />
        <button onClick={this.addRow}>add</button>
        {i > 0 && <button onClick={this.deleteRow}>delete</button>}
      </div>
    );
  };
  render() {
    const { rowCount } = this.state;
    return <div>{times(rowCount, this.renderRow)}
      <br /><br />
      problems
      <p>when there is more input, says i enter something in the input, fill something, then click remove, the value is filled in other value</p>
    </div>
  }
}

To reproduce click add, fill in some values in the 2nd input, then click delete for the second row, the value of the input is there.

Demo https://codesandbox.io/s/4x0x17zykx

回答1:

import React from "react";
import ReactDOM from "react-dom";

export class MultipleInput extends React.Component {
  state = {
    rowCount: 1
  };
  addRow = () => {
    this.setState(({ rowCount }) => ({
      rowCount: rowCount + 1,
    }));
  };
  deleteRow = () => {
    this.setState(({ rowCount }) => ({
      rowCount: rowCount - 1,
    }));
  };

  renderRow = i => {
    const { type, value } = this.props;
    const { rowCount } = this.state;
    return (
      <div>
        <input type={type} value={value} />
        <button onClick={this.addRow}>add</button>
        {rowCount > 1 && <button onClick={this.deleteRow}>delete</button>}
      </div>
    );
 };
 render() {
    const { rowCount } = this.state;
    return Array(rowCount).fill(1).map(i => this.renderRow(i));
 }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<MultipleInput />, rootElement);

Things to note

You need to increment/decrement your state like as above add on the previous state to update the current state;

In render I created a new array which has rowCount no. of elements, to map over the renderRow method. You don't need lodash for this.

Also the delete button will now be shown, when there is more then one input field in this component. i.e, {rowCount > 1 && <button onClick={this.deleteRow}>delete</button>}



回答2:

You are reducing the array size by 1 when delete is clicked, it will always remove the last row no matter which delete button you clicked since you removed the last element of the array. You need to give a unique id to each row and delete the element with that id from the array, not the last element. Use map function the following way

Array.map((i,idx)=>{this.renderRow(i, idx)})

Now you have a unique incrementing number passed to the renderRow function every time you call it so this number can be used as the id. Pass this id to the input field in the renderRow function

<input type={type} value={value} id={idx} />

Instead of row count, you could maintain an array of these ids, so if you have 1 row, all your array has is the first id which is [0], and for 2 rows [0,1] and so on.

Now when you click delete, pass the id, and remove that specific id from the DOM

deleteRow= (idx) => {
     var elem = document.getElementById(idx);
     if (elem.parentNode) {
         elem.parentNode.removeChild(elem);
     }
 this.setState({//Here you can reduce the row count
                        });
        }