Alaa Ali Alaa Ali - 11 months ago 55
Javascript Question

How do I disable a button based on multiple states in React?

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

. 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) {
handleTypeChange: function(e) {
handleClick: function() {
console.log('Button clicked');
componentDidUpdate: function() {
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 (
<select className='form-control' value={this.state.group_id} onChange={this.handleGroupChange}>
<option value=''>Select group...</option>
<option value='10'>Some group</option>
<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>
<br />
<button className="btn btn-primary" onClick={this.handleClick} disabled={this.state.disable_button}>Save</button>

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 component updates, it calls my
, which then updates a state, which then updates the component, 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.

Answer Source

componentDidUpdate has two props passed in to it, prevProps and prevState as documented. You could use this fact in componentUpdate 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>