jansmolders86 jansmolders86 - 1 month ago 20
Javascript Question

React: Nested onclick also triggers parent

I used the react version of the slick carousel to make a Netflix like carousel.
You can click on a tile and that tile then expands to show the details of that tile.

Example:

enter image description here

This works great thanks to Slicks ability to handle dynamic heights.
I want to add a close button the expanded section (as seen in the far right). But that is where I have an issue.

If I add a close button with a onClick handler, it will always trigger the parent Onclick which shows the expanded section.

The showExpanded onclick function just sets a showDetails state.

So my question is:

How can I set a state by clicking on the close button, without also triggering the wrapping parent.

I tried event.preventDefault() and event.stopPropagation() but that didn't do the trick.

Tile click looks like this:

expandTile(){
this.setState({
showDetails: true,
closeTile: false
});
}


Close button click function as I have it now:

closeTile(e){
e.preventDefault();
e.stopPropagation();
const showDetails = this.state.showDetails;
if(showDetails){
this.setState({
showDetails: false,
closeTile: true
});
}
}


Update: added JSX:

return (
<div className={s.itemPreWrapper} key={`${el.title}-item-${index}`}>
<div className={`${s.item} ${showDetails ? s.showDetails : ''}`}
onClick={self.state.expandItem}
data-index={index}
<div className={s.itemCaret}></div>
<div className={s.imgWrapper}>
<img src={el.itemImage}/>
</div>
<div className={s.overlay}>
{el.title}
</div>
<div className={s.expandedTile} style={{left: '-'+offset+'px'}}>
<div className={s.etItem}>
<div key={`subitem-${index}`} ref="subItem">
<div className="row">
<div className={`${s.etClose}`} onClick={self.state.closeTile}><span></span></div>
<div className="col-xs-12 col-sm-3">
<div className={`${s.etImage}`}>
<img src={el.itemImage} alt="product image" className="img-responsive"/>
</div>
</div>
<div className="col-xs-12 col-sm-9">
<div className="row">
<div className={`${s.etContent} col-xs-12 col-sm-6 col-lg-8`}>
<h2>{itemTitle}</h2>
<p> {el.description}</p>
</div>
<div className={`${s.etMedia} col-xs-12 hidden-sm col-sm-5 col-lg-3`}>
{media}
</div>
</div>
</div>
<div className="col-xs-12 col-md-11">
{optionsElem}
</div>
</div>
</div>
</div>
</div>
</div>
);

Answer

A click event is essentially the result of a mousedown event followed by a mouseup event on the same element, which can propagate around even if stopPropagation is called on a click event.

A possible workaround is to call it on mousedown as well; in its simplest form:

<div onMouseDown={e => e.stopPropagation()} ... />
Comments