React:事件传播的最佳实践(触发父事件,而不是子事件)

React: Best practice for event propagation (trigger parent event, not child event)

我一直在寻找最好的方法来防止反应组件中的 CHILD 元素的事件和 PARENT 元素的触发事件。

假设组件在其状态下有一个项目对象数组,ES6 map 函数为每个项目呈现一个带有图标的按钮。单击按钮时,按钮将被删除。

{this.state.items.map(item => (
    <button ...>...</button>
 ))}

到目前为止,我找到了 3 个解决方案。

1 - event.stopPropagation() 基于 id 或其他一些属性。来自 (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; 被用于某些实现。

我不确定这些解决方案是否真的有必要。详细假设如下:

{this.state.items.map(item => (
    <button type="button" value={item.id} onClick={removeItem}>
        <i className='fas fa-times-circle'></i>
    </button>)
}

在事件处理程序中,您可以使用 currentTarget 来模拟默认的 Event.currentTarget 行为,特别是:

It always refers to the element to which the event handler has been attached, as opposed to Event.target, which identifies the element on which the event occurred.

您的事件处理程序可以是:

removeItem(event) {
   const id = event.currentTarget.value;
   this.setState({
      items: this.state.items.filter(item => item.id != id) //assuming you intended to filter here
   });
}

注意:没有必要阻止默认或传播,因为按钮(按钮类型)的默认点击事件什么也不做,而且您不需要停止传播以防您需要附加其他事件处理程序在层次结构中更高。