user1234
user1234

Reputation: 3159

How to avoid conflicting onclick functions on a React component

I have a component below: there are 2 usecases, when I click on the entire div some function is executed and when I click on just the <img>, some function is executed. I have 2 props defined, onClick, when clicked on the entire div and onIconClick when clicked on the img.

export default class List extends React.Component {
  onClick() {
    this.props.onClick();
  }
  onIconClick() {
    this.props.onIconClick();
  }
  render() {
    return (
      <div style="width:200px, height: 200px" onClick={this.onClick.bind(this)}>
        <img src="delete.png" onClick={this.onIconClick.bind(this)} />
      </div>
    );
  }
}

here is the way I call the component:

export default class MyApp extends React.Component {
  onClick() {
    //some execution
  }
  onIconClick() {
    //some other execution
  }
  render() {
    return (
      <List
        onClick={this.onClick.bind(this)}
        onIconClick={this.onIconClick.bind(this)}
      />
    );
  }
}

Now my issue is the this.onClick.bind(this) gets called all the time even when I click the image, hence I never get to this.onIconClick.bind(this).

I tried reversing the order:

 <List onIconClick={this.onIconClick.bind(this)} onClick={this.onClick.bind(this)} />

still doesn't work, not sure what selection criteria I should use in order to distinguish between these 2 clicks.

Any ideas??

Upvotes: 2

Views: 1561

Answers (2)

RedPandaz
RedPandaz

Reputation: 6246

You can use e.stopPropagation(). If you want to use e.nativeEvent.stopImmediatePropagation(), you can use in the same line.

onIconClick(e) {
    e.stopPropagation();
    //e.nativeEvent.stopImmediatePropagation();
    this.props.onIconClick();
  }

Upvotes: 2

Tu Nguyen
Tu Nguyen

Reputation: 10179

Try this:

class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.onClick = this.onClick.bind(this);
    this.onIconClick = this.onIconClick.bind(this);
  }
  onClick() {
    alert("Parent-onClick()");
  }
  onIconClick() {
    alert("Parent-onIconClick()");
  }
  render() {
    return (
      <div>
        <Child onClick={this.onClick} onIconClick={this.onIconClick} />
      </div>
    );
  }
}

class Child extends React.Component {
  constructor(props) {
    super(props);
    this.onClick = this.onClick.bind(this);
    this.onIconClick = this.onIconClick.bind(this);
  }
  onClick() {
    this.props.onClick();
  }
  onIconClick(e) {
    e.stopPropagation();
    this.props.onIconClick();
  }
  render() {
    let styles = {
      height: "500px",
      backgroundColor: "blue",
      paddingTop: "20px"
    };
    return (
      <div onClick={this.onClick} className="img-wrapper" style={styles}>
        <img
          onClick={this.onIconClick}
          src="https://via.placeholder.com/350x150"
          alt="img"
        />
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<Parent />, rootElement);
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"><div>

The idea is using stopPropagation() method of the SyntheticEvent instance.


Your event handlers will be passed instances of SyntheticEvent, a cross-browser wrapper around the browser’s native event. It has the same interface as the browser’s native event, including stopPropagation() and preventDefault(), except the events work identically across all browsers.

If you find that you need the underlying browser event for some reason, simply use the nativeEvent attribute to get it.


Using the SyntheticEvent 's methods allows our code to behave exactly the same across all browsers.

Upvotes: 4

Related Questions