Penny
Penny

Reputation: 113

React onChange handler is being called multiple times during page load

We're trying to add a onChange handler to one of our custom components - namely, a Checkbox component (the only reason for it being a custom component is so that we can efficiently encapsulate the intermediate HTML attribute). It looks something like this:

<Checkbox
  id="select-all"
  onChange={this.handleSelectAllChange(ids)}
  indeterminate={isIndeterminate}
  checked={areVisibleItemsSelected}
  disabled={isDisabled}
/>

The handler function is structured somewhat like this:

handleSelectAllChange(ids) {
  // omitted code that filters on ids and produces newIds

  this.props.updateIds(newIds);
}

Where this.props.updateIds is a passed-down function that modifies the parent component's state.

The problem is that this function is called about 10 times during page load, which is not intended. I thought it was only called when the actual checkbox element is modified?

Upvotes: 11

Views: 14717

Answers (5)

rii
rii

Reputation: 1648

I just had the same issue... I was able to fix the problem stopping the propagation of the event. Add this in the function being called by your onChange event:

e.stopPropagation();

Upvotes: 5

SHZhao74
SHZhao74

Reputation: 93

this.handleSelectAllChange(ids) means call the function.
You should pass a function object to event handlers. e.g.()=>{this.handleSelectAllChange(ids)}

Upvotes: 0

Egor Stambakio
Egor Stambakio

Reputation: 18126

You should define onClick inside the element itself, and pass a pointer to the handler function:

function Checkbox(props) {
  return (<input type="checkbox" value={props.value} key={props.value} 
    onClick={props.clickHandler} />); // actual onclick
}

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      boxes: ['1', '2', '3'],
    }
  }
  
  handleSelectAllChange(box) {
    console.log(box)
  }
  
  render() {
    const boxes = this.state.boxes.map((b,i) => 
    	<Checkbox value={b} 
        clickHandler={this.handleSelectAllChange.bind(this, b)} // pass click handler
        key={i}/>
    );
    return (
      <div>
         {boxes}
      </div>
    );
  }
}

ReactDOM.render(<App/>, 
	document.querySelector('#app'));
<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="app">Loading...</div>

Upvotes: 0

Murat Karag&#246;z
Murat Karag&#246;z

Reputation: 37584

By declaring it like this onChange={this.handleSelectAllChange(ids)} the method call happens immediately at rendering the CheckBox. With ES6 you can avoid this by using

onChange={() => this.handleSelectAllChange(ids)}

This means you pass a new function which will call handleSelectAllChange on change.

Upvotes: 10

Shubham Khatri
Shubham Khatri

Reputation: 281626

Pass the handler function like

<Checkbox
  id="select-all"
  onChange={this.handleSelectAllChange.bind(this,ids)}
  indeterminate={isIndeterminate}
  checked={areVisibleItemsSelected}
  disabled={isDisabled}
/>

Upvotes: 2

Related Questions