Реакция предотвращает пузырьки событий во вложенных компонентах при щелчке

Вот базовый компонент. У функций <ul> и <li> есть функции onClick. Я хочу только onClick на <li>, а не <ul>. Как я могу достичь этого?

Я играл с e.preventDefault(), e.stopPropagation(), но безрезультатно.

class List extends React.Component {
  constructor(props) {
    super(props);
  }

  handleClick() {
    // do something
  }

  render() {

    return (
      <ul 
        onClick={(e) => {
          console.log('parent');
          this.handleClick();
        }}
      >
        <li 
          onClick={(e) => {
            console.log('child');
            // prevent default? prevent propagation?
            this.handleClick();
          }}
        >
        </li>       
      </ul>
    )
  }
}

// => parent
// => child

Ответы

Ответ 1

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

class List extends React.Component {
  handleClick = e => {
    // do something
  }

  render() {
    return (
      <ul onClick={this.handleClick}>
        <ListItem onClick={this.handleClick}>Item</ListItem> 
      </ul>
    )
  }
}

class ListItem extends React.Component {
  handleClick = e => {
    e.stopPropagation();  //  <------ Here is the magic
    this.props.onClick();
  }

  render() {
    return (
      <li onClick={this.handleClick}>
        {this.props.children}
      </li>       
    )
  }
}

Ответ 2

React использует делегирование событий с одним прослушивателем событий в документе для событий, которые пузырятся, например 'click' в этом примере, что означает, что прекращение распространения невозможно; реальное событие уже распространилось к тому моменту, когда вы взаимодействуете с ним в React. stopPropagation on React синтетическое событие возможно, потому что React обрабатывает распространение синтетических событий внутри.

stopPropagation: function(e){
    e.stopPropagation();
    e.nativeEvent.stopImmediatePropagation();
}

Ответ 3

Это не на 100% идеально, но если вам слишком сложно передавать props в детской → детской моде или создавать Context.Provider/Context.Consumer только для этой цели), и вы имеете дело с другой библиотекой у которого есть собственный обработчик, он запускается раньше вашего, вы также можете попробовать:

   function myHandler(e) { 
        e.persist(); 
        e.nativeEvent.stopImmediatePropagation();
        e.stopPropagation(); 
   }

Насколько я понимаю, метод event.persist предотвращает немедленное возвращение объекта в пул React SyntheticEvent. Поэтому из-за этого event переданное в React, на самом деле не существует к тому времени, когда вы его достигнете! Это происходит у внуков из-за способа, которым React обрабатывает вещи внутренне, сначала проверяя родительский элемент на наличие обработчиков SyntheticEvent (особенно, если у родителя был обратный вызов).

Пока вы не вызываете persist для чего-то, что могло бы создать значительную память для продолжения создания событий, таких как onMouseMove (и вы не создаете какую-либо игру Cookie Clicker, такую как Grandma Cookies), все должно быть прекрасно!

Также обратите внимание: из-за периодического чтения их GitHub мы должны не спускать глаз с будущих версий React, так как они могут в конечном итоге решить некоторые проблемы с этим, поскольку они, похоже, собираются делать свертывание кода React в компиляторе/транспортере.

Ответ 4

У меня были проблемы с получением event.stopPropagation(). Если вы тоже это сделаете, попробуйте переместить его в верхнюю часть функции-обработчика кликов, это было то, что мне нужно было сделать, чтобы событие не всплывало. Пример функции:

  toggleFilter(e) {
    e.stopPropagation(); // If moved to the end of the function, will not work
    let target = e.target;
    let i = 10; // Sanity breaker

    while(true) {
      if (--i === 0) { return; }
      if (target.classList.contains("filter")) {
        target.classList.toggle("active");
        break;
      }
      target = target.parentNode;
    }
  }

Ответ 5

Вы можете избежать пузырей события, проверив цель события.
Например, если вы вложили вложенный элемент div, где у вас есть обработчик для события click, и вы не хотите обрабатывать его, при нажатии на вход вы можете просто передать event.target в свой обработчик и проверить, что обработчик должен быть выполняется на основе свойств цели.
Например, вы можете проверить, if (target.localName === "input") { return}.
Итак, это способ "избежать" выполнения обработчика

Ответ 6

Новый способ сделать это намного проще и сэкономит вам время! Просто передайте событие в исходный обработчик щелчка и вызовите preventDefault(); ,

clickHandler(e){
    e.preventDefault();
    //Your functionality here
}