I have been searching for the best way to prevent the event for the CHILD element and trigger event for the PARENT element in react component.
Let's say the component has an array of item object in its state and ES6 map
function renders a button with icon in it for each item. When a button is clicked, the button is removed.
{this.state.items.map(item => (
<button ...>...</button>
))}
So far, I have found of 3 solutions.
1 - event.stopPropagation() based on id or some other attribute. From (How to ONLY trigger parent click event when a child is clicked)
<button id='parent' onClick={removeItem}>
<i id='child' className='fas fa-times-circle'></i>
</button>
removeItem(event) {
const target = event.target;
const id = target.id;
event.stopPropagation();
event.preventDefault();
if(event.target === 'parent') {
this.setState({
items: this.state.items.map(item => item.id != id)
});
}
}
2 - Pass parameters to event handler instead of event itself
<button onClick={() => removeItem(item.id)}>
<i className='fas fa-times-circle'></i>
</button>
removeItem(id) {
this.setState({
items: this.state.items.map(item => item.id != id)
});
}
Cons: It is inefficient because a new reference to the event handler is recreated at every render.
3 - Repeat custom attribute on parent and all child elements
<button itemid={item.id} onClick={removeItem}>
<i itemid={item.id} className='fas fa-times-circle'></i>
</button>
removeItem(event) {
const id = event.target.getAttribute('itemid');
this.setState({
items: this.state.items.map(item => item.id != id)
});
}
Cons: must ensure that all child elements down the DOM tree have itemid={item.id}
, which is difficult in this case (think of svg elements like polygon
).
What is the best way? I've seen pointer-events: none;
be used with some implementations, too.