单击时,React会阻止嵌套组件中的事件冒泡

dmw*_*268 85 onclick event-propagation reactjs

这是一个基本组件.无论是<ul><li>拥有的onClick功能.我只想点击on on <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
Run Code Online (Sandbox Code Playgroud)

Wil*_*one 115

我遇到过同样的问题.我发现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>       
    )
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 真棒!它就像一个魅力! (3认同)
  • 除了stopPropogation外还有其他方法吗? (2认同)
  • 诸如“&lt;Link&gt;”之类的本机组件怎么样 (2认同)
  • 这不是回答错误的问题吗?OP 要求 ListItem 来处理该事件。解决方案是让 List 来处理它。(除非我误会了什么。) (2认同)

Pri*_*han 48

React使用事件委托在文档上使用单个事件侦听器来处理冒泡的事件,例如本例中的"click",这意味着无法停止传播; 当你在React中与它交互时,真实事件已经传播了.由于React在内部处理合成事件的传播,因此可以对React的合成事件进行stopPropagation.

stopPropagation: function(e){
    e.stopPropagation();
    e.nativeEvent.stopImmediatePropagation();
}
Run Code Online (Sandbox Code Playgroud)

  • 有时这可能不起作用-例如,如果您正在使用Material-UI(www.material-ui.com)之类的库,或者将处理程序包装在另一个组件的回调中。但是,如果直接使用自己的代码,就可以了! (2认同)

Tob*_*ist 44

关于 DOM 事件的顺序:CAPTURING vs BUBBLING

事件如何传播有两个阶段。这些被称为“捕获”“冒泡”

               | |                                   / \
---------------| |-----------------   ---------------| |-----------------
| element1     | |                |   | element1     | |                |
|   -----------| |-----------     |   |   -----------| |-----------     |
|   |element2  \ /          |     |   |   |element2  | |          |     |
|   -------------------------     |   |   -------------------------     |
|        Event CAPTURING          |   |        Event BUBBLING           |
-----------------------------------   -----------------------------------
Run Code Online (Sandbox Code Playgroud)

捕获阶段首先发生,然后是冒泡阶段。当您使用常规 DOM api 注册事件时,默认情况下事件将成为冒泡阶段的一部分,但这可以在创建事件时指定

               | |                                   / \
---------------| |-----------------   ---------------| |-----------------
| element1     | |                |   | element1     | |                |
|   -----------| |-----------     |   |   -----------| |-----------     |
|   |element2  \ /          |     |   |   |element2  | |          |     |
|   -------------------------     |   |   -------------------------     |
|        Event CAPTURING          |   |        Event BUBBLING           |
-----------------------------------   -----------------------------------
Run Code Online (Sandbox Code Playgroud)

在 React 中,冒泡事件也是你默认使用的。

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

// handleClick is a CAPTURING (synthetic) event
<button onClickCapture={handleClick}></button>
Run Code Online (Sandbox Code Playgroud)

让我们来看看我们的 handleClick 回调(React):

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

// BUBBLING events
button.addEventListener('click', handleClick, false)
button.addEventListener('click', handleClick)
Run Code Online (Sandbox Code Playgroud)
// handleClick is a BUBBLING (synthetic) event
<button onClick={handleClick}></button>

// handleClick is a CAPTURING (synthetic) event
<button onClickCapture={handleClick}></button>
Run Code Online (Sandbox Code Playgroud)

我没有看到这里提到的另一种选择

如果在所有事件中调用 e.preventDefault() ,则可以检查事件是否已被处理,并防止再次处理它:

function handleClick(e) {
  // This will prevent any synthetic events from firing after this one
  e.stopPropagation()
}
Run Code Online (Sandbox Code Playgroud)

合成事件和原生事件的区别参见 React 文档:https : //reactjs.org/docs/events.html

  • 这应该是公认的答案。你真的不应该使用 stopPropagation。我强烈建议阅读这篇文章:https://css-tricks.com/dangers-stopping-event-propagation/ (4认同)
  • 我只想说,除了使用“onClickCapture”时,没有任何效果。然后使用 event.stopProgatation() 或 event.stopImmediatePropagation() 终于成功了。**未来开发人员请注意** - 如果有一个 3rd 方软件包具有您需要避免的点击处理程序,请执行上述操作,它将阻止其触发。否则,如果您使用“onClick”,它不会给您实际需要的结果。 (3认同)
  • `event.preventDefault()` 和 `event.defaultPrevented` 建议对我有用 (2认同)

ril*_*lar 17

这是防止单击事件前进到下一个组件然后调用 yourFunction 的简单方法。

<Button onClick={(e)=> {e.stopPropagation(); yourFunction(someParam)}}>Delete</Button>
Run Code Online (Sandbox Code Playgroud)


rob*_*b2d 6

这是不是100%完美,但如果它要么是太痛苦的向下传递props的孩子- >儿童时装或创建Context.Provider/Context.Consumer 用于此目的),而你处理的是有它自己的处理器运行的另一个库在你之前,你也可以尝试:

   function myHandler(e) { 
        e.persist(); 
        e.nativeEvent.stopImmediatePropagation();
        e.stopPropagation(); 
   }
Run Code Online (Sandbox Code Playgroud)

据我了解,该event.persist方法可防止对象立即被扔回 React 的SyntheticEvent池中。因此,event当您到达 React 时,传入的 React 实际上并不存在!这发生在孙子中是因为 React 在内部处理事情的方式是首先检查父级的SyntheticEvent处理程序(特别是如果父级有回调)。

只要您不调用persist会产生重要记忆的东西来继续创建事件onMouseMove(并且您没有创建某种 Cookie Clicker 游戏,例如 Grandma's Cookies),它应该完全没问题!

另请注意:通过偶尔阅读他们的 GitHub,我们应该密切关注 React 的未来版本,因为他们最终可能会解决一些与此有关的痛苦,因为他们似乎打算在编译器/转译器中制作折叠 React 代码。


Gil*_*oot 5

如果您希望发生嵌套元素中的操作而不是父元素中的操作,那么,您可以从父元素的操作处理程序中检查目标的类型,然后基于该类型执行操作,即如果目标是我们的嵌套元素,我们什么也不做。否则两个处理程序都会被调用。

// Handler of the parent element. Let's assume the nested element is a checkbox
function handleSingleSelection(e) {
    if(e.target.type !== 'checkbox') {
        // We do not do anything from the 
        // parent handler if the target is a checkbox ( our nested element)
        // Note that the target will always be the nested element
        dispatch(lineSelectionSingle({ line }))
    }
}
Run Code Online (Sandbox Code Playgroud)