I'm building a form with React and I wanted to disable a button when the form is not 'valid', i.e. when one of the states is blank. The button looks at a state called disable_button
. Here's what I have so far:
var MyForm = React.createClass({
getInitialState: function() {
return {
group_id: '',
ls_type_id: '',
disable_button: false
};
},
handleGroupChange: function(e) {
this.setState({group_id: e.target.value});
},
handleTypeChange: function(e) {
this.setState({ls_type_id: e.target.value});
},
handleClick: function() {
console.log('Button clicked');
},
ponentDidUpdate: function() {
this.isFormValid();
},
isFormValid: function(){
if (this.state.group_id == '' || this.state.ls_type_id == '') {
this.setState({disable_button: true});
} else {
this.setState({disable_button: false});
}
},
render: function() {
return (
<div>
<select className='form-control' value={this.state.group_id} onChange={this.handleGroupChange}>
<option value=''>Select group...</option>
<option value='10'>Some group</option>
</select>
<br />
<select className='form-control' value={this.state.ls_type_id} onChange={this.handleTypeChange}>
<option value=''>Select type...</option>
<option value='11'>Some type</option>
</select>
<br />
<button className="btn btn-primary" onClick={this.handleClick} disabled={this.state.disable_button}>Save</button>
</div>
);
}
});
ReactDOM.render(<MyForm />, document.getElementById('content'));
Running this code results in an Uncaught RangeError: Maximum call stack size exceeded
and I realize why: it's because after the ponent updates, it calls my ponentDidUpdate
, which then updates a state, which then updates the ponent, and the loop occurs. So I don't really know how can I make the button disable when one of those states is blank. I might add more form fields so I didn't want to hardcode it to only look at these two selects.
I'm building a form with React and I wanted to disable a button when the form is not 'valid', i.e. when one of the states is blank. The button looks at a state called disable_button
. Here's what I have so far:
var MyForm = React.createClass({
getInitialState: function() {
return {
group_id: '',
ls_type_id: '',
disable_button: false
};
},
handleGroupChange: function(e) {
this.setState({group_id: e.target.value});
},
handleTypeChange: function(e) {
this.setState({ls_type_id: e.target.value});
},
handleClick: function() {
console.log('Button clicked');
},
ponentDidUpdate: function() {
this.isFormValid();
},
isFormValid: function(){
if (this.state.group_id == '' || this.state.ls_type_id == '') {
this.setState({disable_button: true});
} else {
this.setState({disable_button: false});
}
},
render: function() {
return (
<div>
<select className='form-control' value={this.state.group_id} onChange={this.handleGroupChange}>
<option value=''>Select group...</option>
<option value='10'>Some group</option>
</select>
<br />
<select className='form-control' value={this.state.ls_type_id} onChange={this.handleTypeChange}>
<option value=''>Select type...</option>
<option value='11'>Some type</option>
</select>
<br />
<button className="btn btn-primary" onClick={this.handleClick} disabled={this.state.disable_button}>Save</button>
</div>
);
}
});
ReactDOM.render(<MyForm />, document.getElementById('content'));
Running this code results in an Uncaught RangeError: Maximum call stack size exceeded
and I realize why: it's because after the ponent updates, it calls my ponentDidUpdate
, which then updates a state, which then updates the ponent, and the loop occurs. So I don't really know how can I make the button disable when one of those states is blank. I might add more form fields so I didn't want to hardcode it to only look at these two selects.
-
Just call the
isFormValid
method in the change handlers. You don't need aponentDidUpdate
method. – Matthew Herbst Commented Sep 9, 2016 at 1:05 - 2 Any value that can be calculated during render, should be calculated during render. – Dan Prince Commented Sep 9, 2016 at 1:06
2 Answers
Reset to default 4Try this instead:
isFormValid: function(){
return this.state.group_id == '' || this.state.ls_type_id == '';
}
...
<button disabled={this.isFormValid()} ...>
ponentDidUpdate
has two props passed in to it, prevProps
and prevState
as documented. You could use this fact in ponentUpdate
to only call isFormValid
if either the type_id
or ls_type_id
has changed.
However, the cascading setState calls are a little inefficient. It might make more sense to determine disable_button
in your render function, since you don't appear to be consuming it anywhere else. So, delete isFormValid
and all calls to it, and put this in the beginning of render:
render: function () {
var disable_button = false;
if (this.state.group_id == '' || this.state.ls_type_id == '') {
disable_button = true;
}
return ( <div> ...content </div>
}