ReactJS SyntheticEvent stopPropagation () chỉ hoạt động với các sự kiện React?


126

Tôi đang cố gắng sử dụng sự kiện cũng được đính kèm trong React và stopPropagation () của JQuery không dừng lan truyền đến các sự kiện được đính kèm với React.

Có cách nào để làm cho stopPropagation () hoạt động trên các sự kiện này không? Tôi đã viết một JSFiddle đơn giản để thể hiện những hành vi này:

/** @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
Trình lắng nghe sự kiện thực tế của React cũng nằm ở thư mục gốc của tài liệu, nghĩa là sự kiện nhấp chuột đã sủi bọt vào thư mục gốc. Bạn có thể sử dụng event.nativeEvent.stopImmediatePropagationđể ngăn người nghe sự kiện khác bắn, nhưng thứ tự thực hiện không được đảm bảo.
Ross Allen

3
Trên thực tế, stopImmediatePropagationngười nghe yêu cầu sự kiện sẽ được gọi theo thứ tự mà họ bị ràng buộc. Nếu React JS của bạn được khởi tạo trước jQuery của bạn (như trong fiddle của bạn), việc ngừng lan truyền ngay lập tức sẽ hoạt động.
Ross Allen

React ngăn người nghe jQuery không được gọi: jsfiddle.net/7LEDT/5 Không thể để jQuery ngăn chặn React được gọi vì trình nghe jQuery bị ràng buộc sau đó trong fiddle của bạn.
Ross Allen

Một tùy chọn sẽ là thiết lập trình xử lý sự kiện jQuery của riêng bạn componentDidMount, nhưng nó có thể can thiệp vào các trình xử lý sự kiện React khác theo những cách không mong muốn.
Douglas

Tôi nhận ra ví dụ thứ hai về việc .stop-propagationnhất thiết sẽ không hoạt động. Ví dụ của bạn sử dụng phân quyền sự kiện nhưng đang cố gắng ngừng lan truyền tại phần tử. Người nghe cần được ràng buộc với chính yếu tố : $('.stop-propagation').on('click', function(e) { e.stopPropagation(); });. Fiddle
Ross Allen

Câu trả lời:


165

React sử dụng phân quyền sự kiện với một trình lắng nghe sự kiện duy nhất documentcho các sự kiện bong bóng, như 'nhấp chuột' trong ví dụ này, điều đó có nghĩa là không thể truyền bá; sự kiện thực sự đã được lan truyền theo thời gian bạn tương tác với nó trong React. stopPropagationtrên sự kiện tổng hợp của React là có thể bởi vì React xử lý việc truyền bá các sự kiện tổng hợp trong nội bộ.

Làm việc với JSFiddle với các bản sửa lỗi từ bên dưới.

React Stop Propagation trên jQuery Event

Sử dụng Event.stopImmediatePropagationđể ngăn chặn các trình nghe khác (jQuery trong trường hợp này) của bạn trên thư mục gốc được gọi. Nó được hỗ trợ trong IE9 + và các trình duyệt hiện đại.

stopPropagation: function(e){
    e.stopPropagation();
    e.nativeEvent.stopImmediatePropagation();
},
  • Hãy cẩn thận: Người nghe được gọi theo thứ tự mà họ bị ràng buộc. Phản ứng phải được khởi tạo trước khi mã khác (jQuery ở đây) để làm việc này.

jQuery Stop Propagation on React Event

Mã jQuery của bạn cũng sử dụng phân quyền sự kiện, điều đó có nghĩa là việc gọi stopPropagationtrình xử lý không dừng lại; sự kiện đã được truyền bá documentvà người nghe của React sẽ được kích hoạt.

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

Để ngăn chặn sự lan truyền vượt ra ngoài phần tử, người nghe phải bị ràng buộc với chính phần tử đó:

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

Chỉnh sửa (2016/01/14): Làm rõ rằng ủy nhiệm chỉ nhất thiết được sử dụng cho các sự kiện bong bóng. Để biết thêm chi tiết về xử lý sự kiện, nguồn của React có các nhận xét mô tả: ReactBrowserEventEuctor.js .


@ssorellen: Làm rõ: React có ràng buộc trình nghe sự kiện của nó trên documenthoặc thành phần React gốc không? Các trang liên kết chỉ nói "ở cấp cao nhất", mà tôi làm để có nghĩa là nó không những document(nhưng tôi không thể tìm ra nếu điều này thậm chí còn liên quan).
dùng128216

2
@FighterJet Điều đó phụ thuộc vào loại sự kiện. Đối với các sự kiện bong bóng, ủy quyền cấp cao nhất được sử dụng. Đối với các sự kiện không có bong bóng, React nhất thiết phải lắng nghe trên các nút DOM khác nhau. Một mô tả kỹ lưỡng hơn được bao gồm trong ReactBrowserEventEuctor.js: github.com/facebook/react/blob/
Ross Allen

Tôi xin lỗi cho downvote tạm thời. Tôi cần nó cho một báo cáo lỗi và tôi đã thay thế nó bằng một upvote :)
Glorfindel

Ngoài ra, hãy kiểm tra câu trả lời của Jim, gợi ý thêm trình nghe nhấp chuột toàn cầu windowthay vì document: stackoverflow.com/a/52879137/438273
jsejcksn

13

Đáng lưu ý (từ vấn đề này ) rằng nếu bạn đang đính kèm các sự kiện document, e.stopPropagation()sẽ không có ích. Như một giải pháp window.addEventListener()thay thế , bạn có thể sử dụng thay vì document.addEventListener, sau đó event.stopPropagation()sẽ ngăn sự kiện truyền sang cửa sổ.


Cảm ơn rât nhiều! Đây chính xác là những gì tôi có và giải pháp này hoạt động.
Anh Trần

10

Đó vẫn là một khoảnh khắc xen kẽ:

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

Sử dụng cấu trúc này, nếu chức năng của bạn được bao bọc bởi thẻ


1
event.nativeEventlà câu trả lời đúng; Tôi đã có thể sử dụng composedPath()bằng cách này:event.nativeEvent.composedPath()
jimmont

Ý bạn là wrapped by taggì bạn có thể xin vui lòng cung cấp một ví dụ?
JimmyLv

@JimmyLv Ý tôi là <div onClick=(firstHandler)> <div onClick=(secHandler)>active text</div> </div>
La Mã

7

Tôi đã có thể giải quyết điều này bằng cách thêm phần sau vào thành phần của mình:

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

2
Điều này sẽ dừng SynteticEvents hoàn toàn, bởi vì React sử dụng phân quyền sự kiện với một trình nghe sự kiện duy nhất trên tài liệu cho các sự kiện bong bóng.
Vakhtang

5

Tôi đã gặp vấn đề này ngày hôm qua, vì vậy tôi đã tạo ra một giải pháp thân thiện với React.

Kiểm tra phản ứng-bản địa-người nghe . Nó hoạt động rất tốt cho đến nay. Phản hồi đánh giá cao.


5
react-native-listenerviệc sử dụng findDomNodesẽ không được chấp nhận github.com/yannickcr/eslint-plugin-react/issues/
triệt

Bị từ chối vì câu trả lời không phải là nơi thích hợp để tiếp thị hoặc cung cấp các giải pháp bên ngoài không bổ sung cho câu trả lời hoàn chỉnh.
jimmont

2

Từ tài liệu React : Các trình xử lý sự kiện bên dưới được kích hoạt bởi một sự kiện trong giai đoạn sủi bọt . Để đăng ký một trình xử lý sự kiện cho giai đoạn chụp, hãy thêm Capture . (nhấn mạnh thêm)

Nếu bạn có một trình lắng nghe sự kiện nhấp trong mã React của bạn và bạn không muốn nó nổi lên, tôi nghĩ những gì bạn muốn làm là sử dụng onClickCapturethay vì onClick. Sau đó, bạn sẽ chuyển sự kiện cho người xử lý và làm event.nativeEvent.stopPropagation()để giữ cho sự kiện bản địa không bị sủi bọt cho người nghe sự kiện vanilla JS (hoặc bất cứ điều gì không phản ứng).


0

Cập nhật: Bây giờ bạn có thể <Elem onClick={ proxy => proxy.stopPropagation() } />


1
Xem câu trả lời của @ RossAllen. Điều này sẽ không ngăn cản sự lan truyền đến các trình nghe DOM gốc của tổ tiên (mà jQuery sử dụng).
Ben Mosher

Vâng, đây là cách đúng đắn nếu bạn đang sử dụng một thành phần phản ứng. Đánh dấu sự kiện không phải là một ý tưởng tốt.
Eric Hodonsky

Nếu có điều gì đó không thành công, đó là vì bạn đang làm sai điều gì đó
Eric Hodonsky

1
Tôi đồng ý rằng đó là cách chính xác nếu tất cả người nghe của bạn được đính kèm qua React, nhưng đó không phải là câu hỏi ở đây.
Ben Mosher

Đó chỉ là tôi ... Tôi sẽ luôn khuyến khích sử dụng đúng cách thay vì dẫn dắt ai đó lạc lối với một công việc xung quanh có thể khiến họ đau buồn trong tương lai vì họ có "giải pháp" cho một vấn đề.
Eric Hodonsky

0

Một cách giải quyết nhanh chóng là sử dụng window.addEventListenerthay vì document.addEventListener.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.