Реакция: Лучшая практика для распространения события (инициировать родительское событие, а не дочернее событие) - PullRequest
0 голосов
/ 28 января 2019

Я искал лучший способ предотвратить событие для элемента CHILD и событие триггера для элемента PARENT в компоненте реагирования.

Допустим, компонент имеет в своем состоянии массив объекта item иФункция ES6 map отображает кнопку со значком для каждого элемента.Когда кнопка нажата, кнопка удаляется.

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

До сих пор я нашел 3 решения.

1 - event.stopPropagation (), основанный на id или каком-либо другом атрибуте,С ( Как ТОЛЬКО вызвать событие родительского щелчка при нажатии дочернего элемента )

<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}, что в данном случае сложно (представьте себе элементы svg, такие как polygon).

Каков наилучший способ?Я видел, что pointer-events: none; также может использоваться с некоторыми реализациями.

1 Ответ

0 голосов
/ 28 января 2019

Я не уверен, что какое-либо из этих решений действительно необходимо.Для уточнения предположим следующее:

{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
   });
}

Примечание: нет необходимости предотвращать распространение по умолчанию или распространение, поскольку событие нажатия кнопки по умолчанию (типа кнопки) ничего не делает, а также вам не нужно останавливать распространение в случае, если вам нужно присоединить другоеобработчики событий выше в иерархии.

...