ReactJS SyntheticEvent stopPropagation () yalnızca React olaylarıyla mı çalışır?


126

Bir tıklama olayının köpürmesini ve eski kodda JQuery ile eklenmiş bir tıklama olayını tetiklemesini durdurmak için bir ReactJS bileşeni içinde event.stopPropagation () kullanmaya çalışıyorum, ancak React'in stopPropagation () yalnızca olaylara yayılmayı durduruyor gibi görünüyor React'e de eklenmiştir ve JQuery'nin stopPropagation () işlevi, React ile eklenmiş olaylara yayılmayı durdurmaz.

StopPropagation () işlevinin bu olaylarda çalışmasını sağlamanın bir yolu var mı? Bu davranışları göstermek için basit bir JSFiddle yazdım :

/** @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'in gerçek olay dinleyicisi de belgenin kökündedir, yani click olayı zaten kökten köpürmüştür. event.nativeEvent.stopImmediatePropagationDiğer olay dinleyicilerinin tetiklenmesini önlemek için kullanabilirsiniz , ancak yürütme sırası garanti edilmez.
Ross Allen

3
Aslında, stopImmediatePropagationtalep olay dinleyicileri bağlı oldukları sıraya göre çağrılacaktır. React JS'niz jQuery'nizden önce başlatılırsa (kemanınızda olduğu gibi), yayılmayı hemen durdurmak işe yarayacaktır.
Ross Allen

JQuery dinleyicilerinin çağrılmasını durduran tepki: jsfiddle.net/7LEDT/5 jQuery'nin React'in çağrılmasını engellemesi mümkün değildir çünkü jQuery dinleyicileri daha sonra kemanınıza bağlanır.
Ross Allen

Bir seçenek, kendi jQuery olay işleyicinizi içinde componentDidMountkurmak olabilir, ancak bu, diğer React olay işleyicilerine beklenmedik şekillerde müdahale edebilir.
Douglas

İkinci örneğin .stop-propagationmutlaka işe yaramayacağını fark ettim . Örneğiniz olay yetkilendirmesini kullanıyor ancak öğedeki yayılmayı durdurmaya çalışıyor. Dinleyici elemanı kendisine bağlı gerekiyor: $('.stop-propagation').on('click', function(e) { e.stopPropagation(); });. Bu keman, denediğiniz gibi yayılmayı engeller: jsfiddle.net/7LEDT/6
Ross Allen

Yanıtlar:


165

React, documentbu örnekteki 'tıklama' gibi kabarcık oluşturan olaylar için tek bir olay dinleyicisi ile olay yetkilendirmesini kullanır , bu da yayılmayı durdurmanın mümkün olmadığı anlamına gelir; gerçek olay, React'te onunla etkileşim kurduğunuzda zaten yayılmıştır. stopPropagationReact'in sentetik olayı, React'in dahili olarak sentetik olayların yayılmasını yönetmesi nedeniyle mümkündür.

JSFiddle'ı aşağıdan düzeltmelerle çalışmak .

JQuery Olayında Yayılmayı Durdurma React

Event.stopImmediatePropagationKökteki diğer (bu durumda jQuery) dinleyicilerinizin çağrılmasını önlemek için kullanın . IE9 + ve modern tarayıcılarda desteklenmektedir.

stopPropagation: function(e){
    e.stopPropagation();
    e.nativeEvent.stopImmediatePropagation();
},
  • Uyarı: Dinleyiciler, bağlı oldukları sıraya göre çağrılır. Bunun çalışması için React, diğer kodlardan (jQuery burada) önce başlatılmalıdır.

jQuery React Olayında Yayılmayı Durdur

JQuery kodunuz olay yetkilendirmesini de kullanır, bu da stopPropagationişleyicide aramanın hiçbir şeyi durdurmadığı anlamına gelir ; olay zaten yayılmıştır documentve React'in dinleyicisi tetiklenecektir.

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

Öğenin ötesine yayılmayı önlemek için dinleyicinin öğenin kendisine bağlanması gerekir:

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

Düzenleme (2016/01/14): Yetkilendirmenin yalnızca balon oluşturan etkinlikler için kullanılması gerektiği açıklandı . Olay işleme hakkında daha fazla ayrıntı için, React'in kaynağında açıklayıcı yorumlar bulunur: ReactBrowserEventEmitter.js .


@ssorellen: Açıklama: React olay dinleyicisini documentmi yoksa kök React bileşenini mi bağlar ? Bağlantılı sayfa sadece diyor bunu demek götürmek, "üst düzeyde" değildocument (bu bile alakalı olup olmadığını ama çözemiyorum).
user128216

2
@FighterJet Bu olay türüne bağlıdır. Kabaran olaylar için üst düzey yetkilendirme kullanılır. Baloncuk olmayan olaylar için, React mutlaka çeşitli DOM düğümlerini dinler. ReactBrowserEventEmitter.js'de daha kapsamlı bir açıklama bulunmaktadır: github.com/facebook/react/blob/…
Ross Allen

Geçici olumsuz oy için özür dilerim. Bir hata raporu için buna ihtiyacım vardı ve onu bir olumlu oyla değiştirdim :)
Glorfindel

Ayrıca Jim'in cevabına da göz windowdocument
jsejcksn

13

Worth (dan belirterek bu konuda size olayları takılarak eğer o) document, e.stopPropagation()yardım gitmiyor. Geçici bir çözüm olarak, window.addEventListener()yerine kullanabilirsiniz document.addEventListener, ardından event.stopPropagation()olayın pencereye yayılmasını durdurur.


Çok teşekkür ederim! Bu tam olarak sahip olduğum şey ve bu çözüm çalışıyor.
Anh Tran

10

Hâlâ ilginç bir an:

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

İşleviniz etiketle sarmalanmışsa bu yapıyı kullanın


1
event.nativeEventdoğru cevap; Şu composedPath()yolu kullanabildim :event.nativeEvent.composedPath()
jimmont

Ne demek wrapped by tagistiyorsun lütfen bir örnek verebilir misiniz?
JimmyLv

@JimmyLv Demek istediğim<div onClick=(firstHandler)> <div onClick=(secHandler)>active text</div> </div>
Roman

7

Bunu bileşenime aşağıdakileri ekleyerek çözebildim:

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

2
Bu, SynteticEvents'i tamamen durduracaktır, çünkü React, kabarcık oluşturan olaylar için belge üzerinde tek bir olay dinleyicisiyle olay yetkilendirmesini kullanır.
Vakhtang

5

Dün bu problemle karşılaştım, bu yüzden React dostu bir çözüm yarattım.

React-native-listener'a göz atın . Şimdiye kadar çok iyi çalışıyor. Geri bildirim takdir edildi.


5
react-native-listenerkullanımdan findDomNodekaldırılacak olan kullanımlar github.com/yannickcr/eslint-plugin-react/issues/…
Bohdan Lyzanets

Yanıtlar, tam bir yanıtı tamamlamayan harici çözümler pazarlamak veya sunmak için uygun bir yer olmadığı için olumsuz oy verildi.
jimmont

2

Gönderen belgelere tepki : Aşağıdaki olay işleyicileri vardır tetiklenen bir olayın köpürme aşamasına . Yakalama aşaması için bir olay işleyicisi kaydetmek için Yakalama ekleyin . (vurgu eklenmiştir)

React kodunuzda bir tıklama olayı dinleyiciniz varsa ve bunun kabarmasını istemiyorsanız, onClickCapturebunun yerine kullanmak istediğinizi düşünüyorum onClick. Ardından olayı işleyiciye iletir ve event.nativeEvent.stopPropagation()yerel olayın bir vanilya JS olay dinleyicisine (veya tepki vermeyen herhangi bir şeye) köpürmesini engellemek için yaparsınız .


0

Güncelleme: Şimdi yapabilirsiniz <Elem onClick={ proxy => proxy.stopPropagation() } />


1
@ RossAllen'ın cevabına bakın. Bu, bir atanın yerel DOM dinleyicilerine (jQuery'nin kullandığı) yayılmasını engellemez.
Ben Mosher

Bir tepki bileşeni kullanıyorsanız bu doğru yoldur. Olayı öne çıkarmak iyi bir fikir değil.
Eric Hodonsky

Başka bir şey başarısız oluyorsa, yanlış bir şey yaptığınız içindir
Eric Hodonsky

1
Tüm dinleyicileriniz React aracılığıyla bağlanırsa bunun doğru yol olduğunu kabul ediyorum, ancak buradaki soru bu değil.
Ben Mosher

Bu sadece benim ... Birini, gelecekte bir soruna 'çözümü' olduğu için kederine neden olabilecek bir çalışma ile yoldan çıkarmak yerine, her zaman doğru yolu doğru kullanmayı teşvik edeceğim.
Eric Hodonsky

0

Hızlı bir çözüm kullanıyor window.addEventListeneryerine document.addEventListener.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.