我一直在寻找在react组件中防止CHILD元素的事件和PARENT元素的触发事件的最佳方法。
假设组件有一个处于其状态的项对象数组,ES6map
函数为每个项呈现一个带有图标的按钮。单击某个按钮时,该按钮将被删除。
{this.state.items.map(item => (
<button ...>...</button>
))}
到目前为止,我已经找到了3个解决方案。
1-基于id或其他属性的event.stopPropagation()。From(单击子项时如何仅触发父项单击事件)
<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;
也可以与一些实现一起使用。
我不确定这些解决方案中的任何一个实际上都是必要的。详细假设如下:
{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
});
}
注意:没有必要阻止默认或传播,因为按钮(类型为button)的默认点击事件是不做任何事情的,而且在需要附加层次结构中更高级别的其他事件处理程序时,也不需要停止传播。