ReactJS SyntheticEvent stopPropagation()はReactイベントでのみ機能しますか?


126

ReactJSコンポーネント内でevent.stopPropagation()を使用して、レガシーコードで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();
    });
});

9
Reactの実際のイベントリスナーもドキュメントのルートにあります。つまり、クリックイベントはすでにルートにバブリングされています。を使用event.nativeEvent.stopImmediatePropagationして他のイベントリスナーが起動しないようにすることができますが、実行順序は保証されません。
ロス・アレン

3
実際、stopImmediatePropagationクレームイベントリスナーは、バインドされた順に呼び出されます。React JSがjQueryの前に初期化されている場合(フィドルのように)、即時伝搬を停止することで機能します。
ロス・アレン

jQueryリスナーが呼び出されないようにするReact :jsfiddle.net/7LEDT/5 jQueryリスナーは後でフィドルでバインドされるため、jQueryがReactが呼び出されないようにすることはできません。
ロス・アレン

1つのオプションは、独自のjQueryイベントハンドラーをで設定するcomponentDidMountことですが、予期しない方法で他のReactイベントハンドラーに干渉する可能性があります。
ダグラス

上の2番目の例は.stop-propagation必ずしも機能しないことに気付きました。あなたの例はイベント委譲を使用していますが、要素で伝播を停止しようとしています。リスナーは要素自体にバインドする必要があります:$('.stop-propagation').on('click', function(e) { e.stopPropagation(); });。このフィドルは、あなたがしようとしていたようなすべての伝播を防ぎます:jsfiddle.net/7LEDT/6
ロス・アレン

回答:


165

Reactはdocument、この例の「クリック」のようにバブルするイベントに対して単一のイベントリスナーがオンになっているイベント委譲を使用します。つまり、伝播を停止することはできません。実際のイベントは、Reactで操作するまでにすでに伝播しています。stopPropagationReactは合成イベントの伝搬を内部で処理するため、Reactの合成イベントが可能です。

ワーキングJSFiddle以下の不具合を修正しています。

jQueryイベントの伝播停止の反応

Event.stopImmediatePropagationルート上の他の(この場合はjQuery)リスナーが呼び出されないようにするために使用します。IE9 +および最新のブラウザーでサポートされています。

stopPropagation: function(e){
    e.stopPropagation();
    e.nativeEvent.stopImmediatePropagation();
},
  • 警告:リスナーは、バインドされている順に呼び出されます。これが機能するには、他のコード(ここではjQuery)の前にReactを初期化する必要があります。

Reactイベントでの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のソースに説明コメント:ReactBrowserEventEmitter.jsがあります。


@ssorellen:説明:Reactはdocument、またはルートReactコンポーネントにイベントリスナーをバインドしますか?リンク先のページには、ちょうど私がそれをすることを意味するために取る、「トップレベルで」と言うではないdocument(これも関連している場合は、私は把握することはできません)。
user128216

2
@FighterJetイベントタイプによって異なります。バブリングするイベントの場合、トップレベルの委任が使用されます。バブリングしないイベントの場合、Reactは必然的にさまざまなDOMノードをリッスンします。より徹底した説明がReactBrowserEventEmitter.jsに含まれています:github.com/facebook/react/blob/...
ロス・アレン

一時的な反対投票に謝罪します。バグレポートに必要でしたが、
賛成投票に

また、グローバルにクリックリスナを追加することを示唆しているジムの答え、チェックアウトwindowの代わりdocumentstackoverflow.com/a/52879137/438273
jsejcksn

13

この問題から)イベントにをアタッチするdocument場合e.stopPropagation()は役に立たないことに注意してください。回避策として、のwindow.addEventListener()代わりにを使用するとdocument.addEventListenerevent.stopPropagation()イベントがウィンドウに伝達されなくなります。


どうもありがとうございました!これはまさに私が持っているものであり、この解決策は機能します。
Anh Tran

10

それはまだ一つの興味深い瞬間です:

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

関数がタグでラップされている場合は、この構造を使用します


1
event.nativeEvent正解です。私はcomposedPath()それを介して使用することができました:event.nativeEvent.composedPath()
ジムモント

どういう意味wrapped by tag?あなたはplsが例を提供できますか?
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が、ドキュメント上の単一のイベントリスナーでイベントの委任を使用して、バブルするイベントに対処するためです。
Vakhtang 2017

5

昨日この問題に遭遇したため、Reactに適したソリューションを作成しました。

react-native-listenerをチェックしてください。これまでのところ非常にうまく機能しています。フィードバックを歓迎します。


5
react-native-listener用途findDomNode廃止される予定github.com/yannickcr/eslint-plugin-react/issues/...を
ボフダンLyzanets

回答は、完全な回答を補完しない外部ソリューションをマーケティングまたは提供するのに適切な場所ではないため、反対票が投じられました。
ジムモント2018

2

Reactのドキュメントから:以下のイベントハンドラーは、バブリングフェーズのイベントによってトリガーされます。キャプチャフェーズのイベントハンドラーを登録するには、Captureを追加します。(強調を追加)

Reactコードにクリックイベントリスナーがあり、それをバブルアップさせたくない場合は、のonClickCapture代わりにを使用することをお勧めしますonClick。次に、イベントをハンドラーに渡し、event.nativeEvent.stopPropagation()ネイティブイベントがバニラJSイベントリスナー(または反応しないもの)にバブリングしないようにします。


0

更新:今することができます <Elem onClick={ proxy => proxy.stopPropagation() } />


1
@RossAllenの回答を参照してください。これは、祖先のネイティブDOMリスナー(jQueryが使用)への伝播を妨げません。
Ben Mosher 2017年

これは、reactコンポーネントを使用している場合は正しい方法です。イベントをハイジャックすることは良い考えではありません。
エリックホドンスキー2017年

他の何かが失敗している場合、それはあなたが何か他のことを間違っているためです
エリック・ホドンスキー

1
すべてのリスナーがReact経由で接続されている場合、これは正しい方法であることに同意しますが、ここでは問題ではありません。
Ben Mosher 2017年

それは私だけです...問題への「解決策」があるため、将来悲しみを引き起こす可能性のある回避策で誰かを迷わせるのではなく、正しい方法の正しい使用を常に奨励します。
エリックホドンスキー2017年

0

window.addEventListener代わりにを使用すると、簡単な回避策が得られdocument.addEventListenerます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.