我一直在寻找防止React组件中CHILD元素事件和PARENT元素触发事件的最佳方法。
比方说,该组件在其状态下具有一组item对象,ES6 map
函数为每个项目呈现一个带有图标的按钮。单击一个按钮后,该按钮将被删除。
{this.state.items.map(item => (
<button ...>...</button>
))}
到目前为止,我已经找到3种解决方案。
1-基于id或其他属性的event.stopPropagation()。来自(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-将参数传递给事件处理程序,而不是事件本身
<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)
});
}
缺点:效率低下,因为在每次渲染时都会重新创建对事件处理程序的新引用。
3-在父元素和所有子元素上重复自定义属性
<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)
});
}
缺点:必须确保DOM树下的所有子元素都具有itemid={item.id}
,在这种情况下这很难(想想像polygon
这样的svg元素)。
什么是最好的方法?我也看到pointer-events: none;
也可用于某些实现。
答案 0 :(得分:0)
我不确定这些解决方案中的任何一个是否确实必要。要详细说明,请假设以下内容:
{this.state.items.map(item => (
<button type="button" value={item.id} onClick={removeItem}>
<i className='fas fa-times-circle'></i>
</button>)
}
在事件处理程序中,您可以使用currentTarget
来模拟默认的Event.currentTarget行为,特别是:
它始终是指事件处理程序所附加的元素,而不是Event.target,后者标识发生事件的元素。
您的事件处理程序可以是:
removeItem(event) {
const id = event.currentTarget.value;
this.setState({
items: this.state.items.filter(item => item.id != id) //assuming you intended to filter here
});
}
注意:无需阻止默认或传播,因为按钮(类型为按钮)的默认click事件不执行任何操作,也不需要停止传播,以防需要在更高级别附加其他事件处理程序。层次结构。