Here's a basic component. Both the <ul>
and <li>
have onClick functions. I want only the onClick on the <li>
to fire, not the <ul>
. How can I achieve this?
I've played around with e.preventDefault(), e.stopPropagation(), to no avail.
class List extends React.Component {
constructor(props) {
super(props);
}
handleClick() {
// do something
}
render() {
return (
<ul
onClick={(e) => {
console.log('parent');
this.handleClick();
}}
>
<li
onClick={(e) => {
console.log('child');
// prevent default? prevent propagation?
this.handleClick();
}}
>
</li>
</ul>
)
}
}
// => parent
// => child
I had the same issue. I found stopPropagation did work. I would split the list item into a separate component, as so:
class List extends React.Component {
handleClick = e => {
// do something
}
render() {
return (
<ul onClick={this.handleClick}>
<ListItem onClick={this.handleClick}>Item</ListItem>
</ul>
)
}
}
class ListItem extends React.Component {
handleClick = e => {
e.stopPropagation();
this.props.onClick();
}
render() {
return (
<li onClick={this.handleClick}>
{this.props.children}
</li>
)
}
}
React uses event delegation with a single event listener on document for events that bubble, like 'click' in this example, which means stopping propagation is not possible; the real event has already propagated by the time you interact with it in React. stopPropagation on React's synthetic event is possible because React handles propagation of synthetic events internally.
stopPropagation: function(e){
e.stopPropagation();
e.nativeEvent.stopImmediatePropagation();
}
The new way to do this is a lot more simple and will save you some time! Just pass the event into the original click handler and call preventDefault();
.
clickHandler(e){
e.preventDefault();
//Your functionality here
}