ReactJS SyntheticEvent stopPropagation () працює лише з подіями React?


126

Я намагаюся використовувати event.stopPropagation () в компоненті ReactJS, щоб зупинити події клацання з пухирців і викликати подію натискання, яка була приєднана до JQuery у застарілому коді, але, схоже, stopPropagation React () лише зупиняє розповсюдження подій також додається в React, і зупинка розширення JQuery () не зупиняє поширення на події, приєднані до 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();
    });
});

9
Фактичний слухач подій React також знаходиться в корені документа, тобто подія клацання вже перекинулося на корінь. Ви можете використовувати event.nativeEvent.stopImmediatePropagationдля запобігання запуску інших слухачів подій, але порядок виконання не гарантується.
Росс Аллен

3
Насправді, stopImmediatePropagationслухачі подій , які претендують на вимоги, будуть називатися в тому порядку, в якому вони були пов'язані. Якщо ваш React JS ініціалізований перед вашим jQuery (як це у вашій скрипці), зупинка негайного поширення буде працювати.
Росс Аллен

Реагуйте, що зупиняє виклик слухачів jQuery: jsfiddle.net/7LEDT/5 Неможливо, щоб jQuery не міг запобігти виклику React, тому що слухачі jQuery пізніше будуть пов'язані у вашій скрипці.
Росс Аллен

Одним із варіантів було б встановити власний обробник подій jQuery componentDidMount, але це може заважати іншим обробникам подій React несподівано.
Дуглас

Я зрозумів, що другий приклад на .stop-propagationобов'язково не спрацює. Ваш приклад використовує делегування подій, але намагається зупинити поширення на елементі. Слухач повинен бути прив'язаний до самого елементу: $('.stop-propagation').on('click', function(e) { e.stopPropagation(); });. Ця скрипка перешкоджає будь-якому розповсюдженню, як ви намагалися: jsfiddle.net/7LEDT/6
Росс Аллен,

Відповіді:


165

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

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

Реагуйте на зупинку розповсюдження на події jQuery

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

stopPropagation: function(e){
    e.stopPropagation();
    e.nativeEvent.stopImmediatePropagation();
},
  • Застереження: слухачі називаються в тому порядку, в якому вони пов'язані. Реакт повинен бути ініціалізований перед іншим кодом (тут jQuery), щоб це працювало.

jQuery Зупиніть розповсюдження на події React

Ваш код 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();
});

Редагувати (01.01.2014): Уточнено, що делегування обов'язково використовується лише для подій, які спливають. Для отримання більш детальної інформації про події, джерело React має описові коментарі: ReactBrowserEventEmitter.js .


@ssorellen: Уточнення: чи React прив'язує свого слухача подій documentдо кореневого компонента React? На пов'язаній сторінці просто сказано "на верхньому рівні", що я вважаю, що це не той document(але я не можу зрозуміти, чи це навіть актуально).
користувач128216

2
@FighterJet Це залежить від типу події. Для подій, які спливають, використовується делегація верхнього рівня. Для подій, які не спливають, React обов'язково слухає різні вузли DOM. Більш детальний опис міститься в ReactBrowserEventEmitter.js: github.com/facebook/react/blob/…
Росс Аллен

Мої вибачення за тимчасовий парад. Я потребував звіт про помилку , і я замінив його upvote :)
Глорфіндел

Також перевірте відповідь Джима, який пропонує додати глобальний клацання слухачеві windowзамість document: stackoverflow.com/a/52879137/438273
jsejcksn

13

Варто зазначити (з цього випуску ), що якщо ви додаєте події document, e.stopPropagation()допомогти не збирається. Як вирішення, ви можете використовувати window.addEventListener()замість document.addEventListener, а потім event.stopPropagation()зупинить події від поширення до вікна.


Велике спасибі! Це саме те, що у мене є, і це рішення працює.
Ань Тран

10

Це все ще один переривчастий момент:

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

Використовуйте цю конструкцію, якщо ваша функція обгорнута тегом


1
event.nativeEvent- правильна відповідь; Мені вдалося скористатися composedPath()цим способом:event.nativeEvent.composedPath()
jimmont

Що ти маєш на увазі wrapped by tag? Ви можете надати приклад?
JimmyLv

@JimmyLv Я маю на увазі <div onClick=(firstHandler)> <div onClick=(secHandler)>active text</div> </div>
Роман

7

Я зміг вирішити це, додавши до мого компонента наступне:

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

2
Це повністю зупинить SynteticEvents, оскільки React використовує делегування подій разом із одним слухачем подій на документ для подій, які спливають.
Вахтанг

5

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

Ознайомтесь із слухачами-реакторами . Наразі це працює дуже добре. Відгуки оцінені.


5
react-native-listenerвикористання, findDomNodeяке буде застарілим github.com/yannickcr/eslint-plugin-react/isissue/…
Богдан Лизанець

Тому що відповіді - це невідповідне місце для продажу або надання зовнішніх рішень, які не доповнюють повну відповідь.
jimmont

2

З документації React : Обробники подій, наведені нижче, ініціюються подією у фазі кипіння . Щоб зареєструвати обробник подій для етапу зйомки, додайте Capture . (наголос додано)

Якщо у вашому коді React у вас є слухач подій клацання, і ви не хочете, щоб він міхурів, я думаю, що onClickCaptureзамість цього ви хочете скористатися onClick. Тоді ви передасте подію оброблювачу і зробите, event.nativeEvent.stopPropagation()щоб утримати подію не киплять до слухача події ванільної JS (або нічого, що не реагує).


0

Оновлення: Ви можете зараз <Elem onClick={ proxy => proxy.stopPropagation() } />


1
Дивіться відповідь @ RossAllen. Це не завадить розповсюдженню рідних DOM-слухачів предків (якими користується jQuery).
Бен Мошер

Ну це правильний спосіб, якщо ви використовуєте компонент реагування. Хай-джейк події не є хорошою ідеєю.
Ерік Ходонський

Якщо щось інше не вдається, це тому, що ви робите щось інше не так
Ерік Ходонський

1
Я погоджуюся, що це правильний спосіб, якщо всі ваші слухачі приєднані через React, але тут не в цьому питання.
Бен Мошер

Це тільки я ... Я завжди буду заохочувати правильне використання правильного способу, а не когось збивати з роботи, яка може спричинити їх горе в майбутньому, оскільки вони мають "рішення" проблеми.
Ерік Ходонський

0

window.addEventListenerЗамість цього використовується швидке вирішення document.addEventListener.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.