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

84

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

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

http://jsfiddle.net/7LEDT/3/

/** @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();
    });
});
  • 7
    Фактический прослушиватель событий React также находится в корне документа, что означает, что событие click уже переместилось в корень. Вы можете использовать event.nativeEvent.stopImmediatePropagation чтобы запретить event.nativeEvent.stopImmediatePropagation других прослушивателей событий, но порядок выполнения не гарантируется.
  • 3
    На самом деле stopImmediatePropagation утверждает, что прослушиватели событий будут вызываться в том порядке, в котором они были связаны. Если ваш React JS инициализируется до вашего jQuery (как в вашей скрипке), остановка немедленного распространения будет работать.
Показать ещё 5 комментариев

5 ответов

115
Лучший ответ

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

Работа с JSFiddle с исправлениями ниже: http://jsfiddle.net/7LEDT/6/

Распространение повторных остановок при событии jQuery

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

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

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

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

// 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 имеет описательные комментарии: https://github.com/facebook/react/blob/3b96650e39ddda5ba49245713ef16dbc52d25e9e/src/renderers/dom/client/ReactBrowserEventEmitter.js#L23

  • 0
    @ssorellen: Уточнение: связывает ли React свой прослушиватель событий с document или корневой компонент React? На связанной странице просто написано «на верхнем уровне», что, как я понимаю, означает, что это не document (но я не могу понять, насколько это актуально).
  • 2
    @FighterJet Это зависит от типа события. Для событий, которые всплывают, используется делегирование верхнего уровня. Для событий, которые не всплывают, React обязательно прослушивает различные DOM-узлы. Более подробное описание включено в ReactBrowserEventEmitter.js: github.com/facebook/react/blob/…
6

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

componentDidMount() {
  ReactDOM.findDOMNode(this).addEventListener('click', (event) => {
    event.stopPropagation();
  }, false);
}
  • 0
    Это полностью остановит SynteticEvents, потому что React использует делегирование событий с одним прослушивателем событий в документе для событий, которые всплывают.
5

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

Отъезд react-native-listener. До сих пор он работал очень хорошо. Обратная связь оценена.

  • 2
    findDomNode react-native-listener использует findDomNode который будет устаревшим github.com/yannickcr/eslint-plugin-react/issues/…
  • 0
    Плохо, потому что ответы не являются подходящим местом для маркетинга или предоставления внешних решений, которые не дополняют полный ответ.
1

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

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

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

  • 0
    event.nativeEvent - правильный ответ; Я был в состоянии использовать composedPath() путем его: event.nativeEvent.composedPath()
1

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

  • 1
    Смотрите ответ @ RossAllen. Это не помешает распространению на родных слушателей DOM предка (которые использует jQuery).
  • 0
    Ну, это правильный путь, если вы используете реактивный компонент. Кража события не очень хорошая идея.
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню