React는 클릭시 중첩 된 구성 요소에서 이벤트 버블 링을 방지합니다.


114

다음은 기본 구성 요소입니다. <ul>및 둘 다 <li>onClick 기능이 있습니다. 나는 onClick 만 <li>발사하고 <ul>. 이것을 어떻게 할 수 있습니까?

나는 e.preventDefault (), e.stopPropagation ()을 가지고 놀았습니다.

class List extends React.Component {
  constructor(props) {
    super(props);
  }

  handleClick() {
    // do something
  }

  render() {

    return (
      <ul 
        onClick={(e) => {
          console.log('parent');
          this.handleClick();
        }}
      >
        <li 
          onClick={(e) => {
            console.log('child');
            // prevent default? prevent propagation?
            this.handleClick();
          }}
        >
        </li>       
      </ul>
    )
  }
}

// => parent
// => child

나는 같은 질문을했다 stackoverflow.com/questions/44711549/...

답변:


161

나는 같은 문제가 있었다. stopPropagation 작동 한다는 것을 알았 습니다. 목록 항목을 별도의 구성 요소로 분할합니다.

class List extends React.Component {
  handleClick = e => {
    // do something
  }

  render() {
    return (
      <ul onClick={this.handleClick}>
        <ListItem onClick={this.handleClick}>Item</ListItem> 
      </ul>
    )
  }
}

class ListItem extends React.Component {
  handleClick = e => {
    e.stopPropagation();  //  <------ Here is the magic
    this.props.onClick();
  }

  render() {
    return (
      <li onClick={this.handleClick}>
        {this.props.children}
      </li>       
    )
  }
}

this.props.handleClick()에서와 ListItem구성 요소가 될 this.props.click?
blankface

3
stopPropogation을 제외한 다른 방법은 없나요?
Ali Sajid

같은 네이티브 구성 요소는 <Link>
어떻습니까

handleClick에 매개 변수를 전달해야하는 경우 어떻게해야합니까?
Manticore

이것은 잘못된 질문에 대한 답이 아닙니까? OP는 이벤트를 처리 할 ListItem을 요청했습니다. 솔루션에는이를 처리하는 목록이 있습니다. (오해하지 않는 한.)
Thomas Jay Rush

57

React는이 예제에서 'click'과 같이 버블 링되는 이벤트에 대해 문서에서 단일 이벤트 리스너와 함께 이벤트 위임을 사용합니다. 이는 전파 중지가 불가능 함을 의미합니다. 실제 이벤트는 React에서 상호 작용할 때 이미 전파되었습니다. React의 합성 이벤트에 대한 stopPropagation은 React가 내부적으로 합성 이벤트의 전파를 처리하기 때문에 가능합니다.

stopPropagation: function(e){
    e.stopPropagation();
    e.nativeEvent.stopImmediatePropagation();
}

매우 유용합니다 .. stopPropagation () 자체가 제대로 작동하지 않았습니다
pravin

1
내가 document.addEventListener('click')react 's와 결합 하여 사용하고 있기 때문에 이것이 나를 위해 일한 것입니다onClick
OtotheA

2
예를 들어 Material-UI (www.material-ui.com)와 같은 라이브러리를 사용하거나 다른 구성 요소의 콜백에 핸들러를 래핑하는 경우 이러한 방법이 작동하지 않을 수 있습니다. 그러나 직접 코드를 작성하면 괜찮습니다!
rob2d 2019

1
@ rob2d, Material-UI를 사용할 때 어떻게 처리합니까?
Italik

@Italik 위에 샘플 함수가 있습니다. 그러나 가상화 / 삼키지 않도록 콜백에서 첫 번째로 즉시 호출해야합니다. 적어도 AFAIK. 고맙게도 최근에이 문제와 싸우지 않았습니다.
rob2d

9

DOM 이벤트 순서 : CAPTURING vs BUBBLING

이벤트가 전파되는 방법에는 두 단계가 있습니다. 이를 "캡처""버블 링"이라고 합니다.

               | |                                   / \
---------------| |-----------------   ---------------| |-----------------
| element1     | |                |   | element1     | |                |
|   -----------| |-----------     |   |   -----------| |-----------     |
|   |element2  \ /          |     |   |   |element2  | |          |     |
|   -------------------------     |   |   -------------------------     |
|        Event CAPTURING          |   |        Event BUBBLING           |
-----------------------------------   -----------------------------------

캡처 단계가 먼저 발생한 다음 버블 링 단계가 이어집니다. 일반 DOM API를 사용하여 이벤트를 등록 할 때 이벤트는 기본적으로 버블 링 단계의 일부가되지만 이벤트 생성시 지정할 수 있습니다.

// CAPTURING event
button.addEventListener('click', handleClick, true)

// BUBBLING events
button.addEventListener('click', handleClick, false)
button.addEventListener('click', handleClick)

React에서 버블 링 이벤트도 기본적으로 사용합니다.

// handleClick is a BUBBLING (synthetic) event
<button onClick={handleClick}></button>

// handleClick is a CAPTURING (synthetic) event
<button onClickCapture={handleClick}></button>

handleClick 콜백 (React) 내부를 살펴 보겠습니다.

function handleClick(e) {
  // This will prevent any synthetic events from firing after this one
  e.stopPropagation()
}
function handleClick(e) {
  // This will set e.defaultPrevented to true
  // (for all synthetic events firing after this one)
  e.preventDefault()  
}

여기서 언급하지 않은 대안

모든 이벤트에서 e.preventDefault ()를 호출하면 이벤트가 이미 처리되었는지 확인하고 다시 처리되지 않도록 할 수 있습니다.

handleEvent(e) {
  if (e.defaultPrevented) return  // Exits here if event has been handled
  e.preventDefault()

  // Perform whatever you need to here.
}

합성 이벤트와 네이티브 이벤트의 차이점은 React 문서 ( https://reactjs.org/docs/events.html)를 참조하십시오.


5

이것은 100 % 적합하지 않습니다,하지만 너무 많은 고통 중 하나 인 경우 아래로 통과하는 props어린이 -> 어린이 패션 또는를 생성 Context.Provider/ Context.Consumer 단지 이러한 목적을 위해), 당신은 자신의 핸들러가 실행될 것있는 다른 라이브러리를 다루고있는 당신보다 먼저 시도해 볼 수도 있습니다.

   function myHandler(e) { 
        e.persist(); 
        e.nativeEvent.stopImmediatePropagation();
        e.stopPropagation(); 
   }

내가 이해 한 바에 따르면이 event.persist메서드는 객체가 React의 SyntheticEvent풀로 즉시 다시 던져지는 것을 방지합니다 . 그렇기 때문에 eventReact 에서 전달 된 것은 실제로 도달 할 때까지 존재하지 않습니다! 이것은 React가 SyntheticEvent핸들러 에 대해 부모를 먼저 확인하여 내부적으로 처리하는 방식 때문에 손자에게서 발생합니다 (특히 부모가 콜백이있는 경우).

persist다음과 같은 이벤트를 계속 생성하기 위해 중요한 메모리를 생성 할 무언가를 호출하지 않는 한 onMouseMove(그리고 할머니의 쿠키와 같은 일종의 쿠키 리모콘 게임을 생성하지 않는 한) 완벽 할 것입니다!

또한 참고 : 가끔씩 GitHub를 읽음으로써 React의 향후 버전 이 컴파일러 / 트랜스 파일러에서 React 코드를 접는 것으로 보이기 때문에 결국이 문제를 해결할 수 있으므로 우리는 React의 향후 버전을 주시해야합니다.


1

event.stopPropagation()일하는 데 문제가 있었습니다. 당신도 그렇게한다면, 그것을 클릭 핸들러 함수의 맨 위로 이동해보십시오. 이벤트가 버블 링되는 것을 막기 위해 제가해야 할 일이었습니다. 예제 함수 :

  toggleFilter(e) {
    e.stopPropagation(); // If moved to the end of the function, will not work
    let target = e.target;
    let i = 10; // Sanity breaker

    while(true) {
      if (--i === 0) { return; }
      if (target.classList.contains("filter")) {
        target.classList.toggle("active");
        break;
      }
      target = target.parentNode;
    }
  }

0

이벤트 대상을 확인하여 이벤트 버블 링을 방지 할 수 있습니다.
예를 들어 클릭 이벤트에 대한 핸들러가있는 div 요소에 중첩 된 입력이 있고이를 처리하고 싶지 않은 경우 입력을 클릭하면 event.target핸들러에 전달 하기 만하면 다음을 기반으로 핸들러가 실행되어야합니다. 대상의 속성.
예를 들어 if (target.localName === "input") { return}.
따라서 핸들러 실행을 "피하는"방법입니다.


-4

이 작업을 수행하는 새로운 방법은 훨씬 더 간단하며 시간을 절약 할 수 있습니다! 이벤트를 원래 클릭 핸들러에 전달하고 preventDefault();.

clickHandler(e){
    e.preventDefault();
    //Your functionality here
}

3
-1; 나는 이것을 테스트했지만 클릭 전파에는 작동하지 않습니다. AFAIK 이것은 기본 링크 기능을 중지하는 링크에 대한 onClick 핸들러를 원하지만 이벤트 버블 링에는 유용하지 않습니다.
Joel Peltonen
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.