2

http://jsbin.com/zehoceloka/1/edit

my input number is dynamic, it depends on the API how many data it has. So firstly I map it to the view. But there is also a feature where user can add new item. I trying to push a new empty array, but nothing happens. Am I doing it wrong?

class HelloWorldComponent extends React.Component {

  constructor(){
    super()
    this.addNewRow = this.addNewRow.bind(this);
    this.state = {
      "rules":[
        "age must be above 10",
        "must wear shoe"
      ]
    }
  }

  addNewRow(e){
    const updated = this.state.rules.push("");
    this.setState({rules:updated});
  }


  render() {
    return (
      <div>
        {this.state.rules.map(obj => 
           <input type="text" defaultValue={obj} />
         )}
         <button>Add New Rules</button>
         <br /><br />
         <pre>{JSON.stringify(this.state.rules,null,2)}</pre>
       </div>
    );
  }
}
Mellisa
  • 525
  • 2
  • 10
  • 19

3 Answers3

1

The objects in the state cannot be modify, you need to extract them, modify and then add again to the state:

addNewRow(e){
  let rules=this.state.rules.slice();
  rules.push('');
  this.setState({rules:rules});
}
Pablo Lozano
  • 9,189
  • 2
  • 34
  • 56
1

You forgot to define the click event on button, use this:

<button onClick={this.addNewRow}>Add New Rules</button>

Few issues in this line:

const updated = this.state.rules.push("");

1.Never mutate the state variable directly by this.state.a.push() or this.state.a = '', always use setState to update the value.

2.a.push() will not return the updated array, it will return the value pushed into array.

From Doc:

Never mutate this.state directly, as calling setState() afterwards may replace the mutation you made. Treat this.state as if it were immutable.

Check this working code:

class HelloWorldComponent extends React.Component {
  
  constructor(){
    super()
    this.addNewRow = this.addNewRow.bind(this);
    this.state = {
      rules:[
        "age must be above 10",
        "must wear shoe"
      ]
    }
  }
  
  addNewRow(e){
    let updated = this.state.rules.slice();
    updated.push("");
    this.setState({rules:updated});
  }
    
  
  render() {
    return (
      <div>
        {this.state.rules.map(obj => 
           <input type="text" defaultValue={obj} />
         )}
         <button onClick={this.addNewRow}>Add New Rules</button>
         <br /><br />
         <pre>{JSON.stringify(this.state.rules,null,2)}</pre>
       </div>
    );
  }
}

ReactDOM.render(
  <HelloWorldComponent />,
  document.getElementById('react_example')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id='react_example'/>
Mayank Shukla
  • 80,295
  • 14
  • 134
  • 129
  • shouldnt you use concat() so you dont mutate the state? `this.setState({rules: this.state.rules.concat(""))}` or using ES6 destructurring, like this: `this.setState({rules: [...this.state.rules, newState] )}` – ardev Apr 02 '18 at 16:49
0

Please try like this:

var arr = this.state.rules.slice();
arr.push("");
this.setState({ rules: arr });
Nitesh
  • 1,211
  • 12
  • 17