ReactJS SyntheticEvent stopPropagation() работает только с событиями React?

Я пытаюсь использовать event.stopPropagation() в компоненте ReactJS, чтобы остановить всплывающее событие клика и запуск события клика, который был присоединен с JQuery в устаревшем коде, но кажется, что React stopPropagation() останавливает распространение только к событиям также прикреплен в React, а JQuery stopPropagation() не останавливает распространение на события, связанные с React.

Есть ли способ заставить stopPropagation() работать через эти события? Я написал простой JSFiddle, чтобы продемонстрировать это поведение:

/** @jsx React.DOM */
var Propagation = React.createClass({
    alert: function(){
        alert('React Alert');
    },
    stopPropagation: function(e){
        e.stopPropagation();
    },
    render: function(){
        return (
            <div>
                <div onClick={this.alert}>
                    <a href="#" onClick={this.stopPropagation}>React Stop Propagation on React Event</a>
                </div>
                <div className="alert">
                    <a href="#" onClick={this.stopPropagation}>React Stop Propagation on JQuery Event</a>
                </div>
                <div onClick={this.alert}>
                    <a href="#" className="stop-propagation">JQuery Stop Propagation on React Event</a>
                </div>
                <div className="alert">
                    <a href="#" className="stop-propagation">JQuery Stop Propagation on JQuery Event</a>
                </div>
            </div>
        );
    }
});

React.renderComponent(<Propagation />, document.body);

$(function(){    
    $(document).on('click', '.alert', function(e){
        alert('Jquery Alert');
    });

    $(document).on('click', '.stop-propagation', function(e){
        e.stopPropagation();
    });
});

Ответ 1

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

Работа JSFiddle с исправлениями снизу.

Реагировать на распространение стоп-сигнала на событии jQuery

Используйте Event.stopImmediatePropagation, чтобы предотвратить вызов других слушателей (в данном случае jQuery) в корневом каталоге. Он поддерживается в IE9+ и современных браузерах.

stopPropagation: function(e){
    e.stopPropagation();
    e.nativeEvent.stopImmediatePropagation();
},
  • Предостережение: слушатели вызываются в том порядке, в котором они связаны. React должен быть инициализирован перед другим кодом (здесь jQuery), чтобы это работало.

jQuery Остановить распространение по событию React

Ваш код jQuery также использует делегирование событий, что означает, что вызов stopPropagation в обработчике ничего не останавливает; событие уже передано в document, и React Listener будет запущен.

// Listener bound to 'document', event delegation
$(document).on('click', '.stop-propagation', function(e){
    e.stopPropagation();
});

Чтобы предотвратить распространение за пределы элемента, слушатель должен быть привязан к самому элементу:

// Listener bound to '.stop-propagation', no delegation
$('.stop-propagation').on('click', function(e){
    e.stopPropagation();
});

Изменить (2016/01/14): Уточнено, что делегирование обязательно используется только для событий, которые всплывают. Для получения дополнительной информации об обработке событий источник React имеет описательные комментарии: ReactBrowserEventEmitter.js.

Ответ 2

Я столкнулся с этой проблемой вчера, поэтому я создал решение, дружественное к React.

Проверьте реагировать-нативный слушатель. Пока все работает очень хорошо. Обратная связь приветствуется.

Ответ 3

Мне удалось решить эту проблему, добавив следующее к моему компоненту:

componentDidMount() {
  ReactDOM.findDOMNode(this).addEventListener('click', (event) => {
    event.stopPropagation();
  }, false);
}

Ответ 4

Это еще один интересный момент:

ev.preventDefault()
ev.stopPropagation();
ev.nativeEvent.stopImmediatePropagation();

Используйте эту конструкцию, если ваша функция обернута тегом

Ответ 5

Стоит отметить (из этой проблемы), что если вы присоединяете события к document, e.stopPropagation() не поможет. В качестве обходного пути вы можете использовать window.addEventListener() вместо document.addEventListener, тогда event.stopPropagation() остановит распространение события на окно.

Ответ 6

Обновление: теперь вы можете <Elem onClick={ proxy => proxy.stopPropagation() } />

Ответ 7

Из React документации: Приведенные ниже обработчики событий запускаются событием в фазе пузырьков. Чтобы зарегистрировать обработчик событий для фазы захвата, добавьте Capture. (выделение добавлено)

Если в вашем коде React имеется прослушиватель событий щелчка, и вы не хотите, чтобы он всплывал, я думаю, вам нужно использовать onClickCapture вместо onClick. Затем вы должны передать событие обработчику и выполнить event.nativeEvent.stopPropagation(), чтобы не дать нативному событию перескочить до обычного прослушивателя событий JS (или чего-либо, что не реагирует).