最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Adding dynamic states in reactJs - Stack Overflow

programmeradmin3浏览0评论

I created a reactJs page that allows an admin add a user to a platform. Now, instead of submitting the form for each new user, the admin can add as many users as possible before submitting the form. By default, one table row containing input fields is displayed and then on click of the add button, a new row is added and the admin can fill the necessary details.

I want to add an onChange event to the input fields for each new row. I don't know how to do as this is quite dynamic. The state will have to change as new rows is added. I don't know how to go about updating this state and adding the onChange event for each field in each row. Here is my existing code:

export default class Admins extends React.Component{
    constructor(props){
        super(props);
        this.state = {
            errors : '',
            success : '',
            rows : [1]
        }
        this.addRow = this.addRow.bind(this);
        this.fetchRows = this.fetchRows.bind(this);
        this.removeRow = this.removeRow.bind(this);
    }
    addRow(){
        var last = this.state.rows[this.state.rows.length-1];
        var current = last + 1;
        this.setState({
            rows : this.state.rows.concat(current)
        });
    }
    removeRow(index){
        var array = this.state.rows;
        array.splice(index, 1)
        this.setState({
            rows : array
        })
    }
    fetchRows(){
        return this.state.rows.map((row, index) => (
            //console.log(row, index)
            <tr key={row}>
                <td className="text-center">
                    <button type="button" onClick={(e)=> this.removeRow(index)} data-toggle="tooltip" className="btn btn-xs btn-danger"
                            data-original-title=""><i className="fa fa-trash"></i>
                    </button>
                </td>
                <td>
                    <input type="text" className="form-control" onChange={}/>
                </td>
                <td>
                    <input type="text" className="form-control" onChange={}/>
                </td>
                <td>
                    <input type="text" className="form-control" onChange={}/>
                </td>
            </tr>
        ));
    }
    render(){
        return(
            <div>
                <Top/>
                <SideBar/>
                <div className="breadcrumb-holder">
                    <div className="container-fluid">
                        <ul className="breadcrumb">
                            <li className="breadcrumb-item"><Link to="/">Dashboard</Link></li>
                            <li className="breadcrumb-item active">Admins</li>
                        </ul>
                    </div>
                </div>
                <section className="forms">
                    <div className="container-fluid">
                        <header>
                            <h3 className="h5 display">Admins</h3>
                        </header>

                        <div className="row">
                            <div className="col-lg-6">
                                <h5 className="text-danger">{this.state.errors}</h5>
                                <h5 className="text-success">{this.state.success}</h5>
                            </div>
                        </div>
                        <div className="row">
                            <div className="col-lg-6">
                                <div className="card">
                                    <div className="card-header d-flex align-items-center">
                                        <h5></h5>
                                    </div>
                                    <div className="card-body">
                                        <table className="table table-bordered">
                                            <thead>
                                            <tr>
                                                <th  width="5%">Actions</th>
                                                <th>Name</th>
                                                <th>Email</th>
                                                <th>Password</th>
                                            </tr>
                                            </thead>
                                            <tbody>
                                                {this.fetchRows()}
                                                <tr>
                                                    <td className="text-center">
                                                        <button type="button" onClick={this.addRow} data-toggle="tooltip" className="btn btn-xs btn-primary"
                                                                data-original-title=""><i className="fa fa-plus"></i>
                                                        </button>
                                                    </td>
                                                </tr>
                                            </tbody>
                                        </table>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </section>
            </div>
        );
    }
}

I created a reactJs page that allows an admin add a user to a platform. Now, instead of submitting the form for each new user, the admin can add as many users as possible before submitting the form. By default, one table row containing input fields is displayed and then on click of the add button, a new row is added and the admin can fill the necessary details.

I want to add an onChange event to the input fields for each new row. I don't know how to do as this is quite dynamic. The state will have to change as new rows is added. I don't know how to go about updating this state and adding the onChange event for each field in each row. Here is my existing code:

export default class Admins extends React.Component{
    constructor(props){
        super(props);
        this.state = {
            errors : '',
            success : '',
            rows : [1]
        }
        this.addRow = this.addRow.bind(this);
        this.fetchRows = this.fetchRows.bind(this);
        this.removeRow = this.removeRow.bind(this);
    }
    addRow(){
        var last = this.state.rows[this.state.rows.length-1];
        var current = last + 1;
        this.setState({
            rows : this.state.rows.concat(current)
        });
    }
    removeRow(index){
        var array = this.state.rows;
        array.splice(index, 1)
        this.setState({
            rows : array
        })
    }
    fetchRows(){
        return this.state.rows.map((row, index) => (
            //console.log(row, index)
            <tr key={row}>
                <td className="text-center">
                    <button type="button" onClick={(e)=> this.removeRow(index)} data-toggle="tooltip" className="btn btn-xs btn-danger"
                            data-original-title=""><i className="fa fa-trash"></i>
                    </button>
                </td>
                <td>
                    <input type="text" className="form-control" onChange={}/>
                </td>
                <td>
                    <input type="text" className="form-control" onChange={}/>
                </td>
                <td>
                    <input type="text" className="form-control" onChange={}/>
                </td>
            </tr>
        ));
    }
    render(){
        return(
            <div>
                <Top/>
                <SideBar/>
                <div className="breadcrumb-holder">
                    <div className="container-fluid">
                        <ul className="breadcrumb">
                            <li className="breadcrumb-item"><Link to="/">Dashboard</Link></li>
                            <li className="breadcrumb-item active">Admins</li>
                        </ul>
                    </div>
                </div>
                <section className="forms">
                    <div className="container-fluid">
                        <header>
                            <h3 className="h5 display">Admins</h3>
                        </header>

                        <div className="row">
                            <div className="col-lg-6">
                                <h5 className="text-danger">{this.state.errors}</h5>
                                <h5 className="text-success">{this.state.success}</h5>
                            </div>
                        </div>
                        <div className="row">
                            <div className="col-lg-6">
                                <div className="card">
                                    <div className="card-header d-flex align-items-center">
                                        <h5></h5>
                                    </div>
                                    <div className="card-body">
                                        <table className="table table-bordered">
                                            <thead>
                                            <tr>
                                                <th  width="5%">Actions</th>
                                                <th>Name</th>
                                                <th>Email</th>
                                                <th>Password</th>
                                            </tr>
                                            </thead>
                                            <tbody>
                                                {this.fetchRows()}
                                                <tr>
                                                    <td className="text-center">
                                                        <button type="button" onClick={this.addRow} data-toggle="tooltip" className="btn btn-xs btn-primary"
                                                                data-original-title=""><i className="fa fa-plus"></i>
                                                        </button>
                                                    </td>
                                                </tr>
                                            </tbody>
                                        </table>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </section>
            </div>
        );
    }
}
Share Improve this question asked Jul 18, 2018 at 10:28 shekwoshekwo 1,4472 gold badges23 silver badges55 bronze badges 2
  • You're mutating your state, which you should never do in react. In removeRow() you're setting the array variable equal to this.state.rows, but that doesn't create a new array, it creates a reference to that array. So on the next line when you call splice() (which mutates the array that calls it), this will actually mutate the state itself. Use slice() to make a copy of the state array, e.g. let currentRows = this.state.rows.slice(0). Also, don't call variables things like 'array', give them meaningful names.. – Jayce444 Commented Jul 18, 2018 at 10:48
  • Also, when you implement your final solution, make sure your keys are unique. Don't use the index as a key (which is pretty much what you're doing at the moment, since row is just an incrementing number). If there's nothing unique about them available from the data, you can generate a unique id and assign it to the row object when you add a row. – Jayce444 Commented Jul 18, 2018 at 10:51
Add a ment  | 

1 Answer 1

Reset to default 7

You could create a method onChange that takes in the event and the index of the row that got changed, and use the name and the value of the input that changed bined with the index of the row in the array to figure out what field to update.

Example

class Admins extends React.Component {
  state = {
    errors: "",
    success: "",
    rows: []
  };

  addRow = () => {
    this.setState(previousState => {
      return {
        rows: [...previousState.rows, { name: "", email: "", password: "" }]
      };
    });
  };

  removeRow = index => {
    this.setState(previousState => {
      const rows = [...previousState.rows];
      rows.splice(index, 1);
      return { rows };
    });
  };

  onChange = (event, index) => {
    const { name, value } = event.target;

    this.setState(previousState => {
      const rows = [...previousState.rows];
      rows[index] = { ...rows[index], [name]: value };
      return { rows };
    });
  };

  render() {
    return (
      <div>
        <div className="breadcrumb-holder">
          <div className="container-fluid">
            <ul className="breadcrumb">
              <li className="breadcrumb-item active">Admins</li>
            </ul>
          </div>
        </div>
        <section className="forms">
          <div className="container-fluid">
            <header>
              <h3 className="h5 display">Admins</h3>
            </header>
            <div className="row">
              <div className="col-lg-6">
                <h5 className="text-danger">{this.state.errors}</h5>
                <h5 className="text-success">{this.state.success}</h5>
              </div>
            </div>
            <div className="row">
              <div className="col-lg-6">
                <div className="card">
                  <div className="card-header d-flex align-items-center">
                    <h5 />
                  </div>
                  <div className="card-body">
                    <table className="table table-bordered">
                      <thead>
                        <tr>
                          <th width="5%">Actions</th>
                          <th>Name</th>
                          <th>Email</th>
                          <th>Password</th>
                        </tr>
                      </thead>
                      <tbody>
                        {this.state.rows.map((row, index) => (
                          <tr key={row}>
                            <td className="text-center">
                              <button
                                type="button"
                                onClick={e => this.removeRow(index)}
                                data-toggle="tooltip"
                                className="btn btn-xs btn-danger"
                                data-original-title=""
                              >
                                <i className="fa fa-trash" />
                              </button>
                            </td>
                            <td>
                              <input
                                type="text"
                                name="name"
                                className="form-control"
                                value={row.name}
                                onChange={e => this.onChange(e, index)}
                              />
                            </td>
                            <td>
                              <input
                                type="text"
                                name="email"
                                className="form-control"
                                value={row.email}
                                onChange={e => this.onChange(e, index)}
                              />
                            </td>
                            <td>
                              <input
                                type="text"
                                name="password"
                                className="form-control"
                                value={row.password}
                                onChange={e => this.onChange(e, index)}
                              />
                            </td>
                          </tr>
                        ))}
                        <tr>
                          <td className="text-center">
                            <button
                              type="button"
                              onClick={this.addRow}
                              data-toggle="tooltip"
                              className="btn btn-xs btn-primary"
                              data-original-title=""
                            >
                              <i className="fa fa-plus" />
                            </button>
                          </td>
                        </tr>
                      </tbody>
                    </table>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </section>
      </div>
    );
  }
}
发布评论

评论列表(0)

  1. 暂无评论