【问题标题】:React: event bubbling through nested componentsReact:通过嵌套组件冒泡的事件
【发布时间】:2015-12-10 05:10:02
【问题描述】:

假设我有这样的嵌套组件:

<root />
  <comp1 />
    <comp2 />
      <target id={this.props.id}>
        <div>click me</div>

我想让点击目标在 root 上运行一个函数:

//on root component
this.action = function(id){}

我是否需要手动设置链中每个组件的属性,就像在 React 教程示例中一样? Jsfiddle

<root />
  <comp1 clickHandler={this.action}/>
    <comp2 clickHandler={this.clickHandler}/>
      <target id={this.props.id} clickHandler={this.clickHandler} />
        <div onClick={this.props.clickHandler.bind(this, this.props.id)}>click me</div>

或者有什么方法可以像在普通 DOM 中一样将事件冒泡?

【问题讨论】:

标签: javascript events reactjs


【解决方案1】:

React 在捕获和冒泡阶段都支持跨其虚拟 DOM 的合成事件(如此处所述:https://facebook.github.io/react/docs/events.html)。

这意味着您可以在根附近的任何 DOM 元素上放置一个 onClick 处理程序,它应该触发页面上的所有 Click 事件:

<root>
  <div onClick={this.handleAllClickEvents}>
    <comp1>
      <comp2>
        <target>
          <div id={this.props.id}>click me</div>

但是,由于它会为所有单击事件触发,因此您需要在单击处理程序中消除它们之间的歧义(这会产生一些非常丑陋的代码)。

function handleAllClickEvents(event) {
  var target = event.relatedTarget;
  var targetId = target.id;
  switch(targetId) {
    case 'myBtn1':
      // handle myBtn1 click event
    case 'myBtn2':
      // handle myBtn2 click event
  }
}

这种事件委托风格实际上是 React 在后台 (https://shripadk.github.io/react/docs/interactivity-and-dynamic-uis.html#under-the-hood-autobinding-and-event-delegation) 所做的事情,所以你必须问问自己这是否是你真正想做的事情。

或者,您可能想查看 Flux 中的 Dispatcher 模式 (https://reactjs.org/blog/2014/07/30/flux-actions-and-the-dispatcher.html)。开始有点复杂,但总体而言这是一个更好的解决方案。

【讨论】:

  • 我以为你不应该变异道具?
  • «对于页面上的所有 Click 事件» 更准确地说,对于所有后代(内部节点)。
【解决方案2】:

您可以使用速记将道具传递给子组件

<Component {...this.props} more="values" />

Transferring props

所以在你的情况下:

<root />
  <comp1 clickHandler={this.action}/>
    <comp2 {...this.props} />
      <target {...this.props} id={this.props.id} />
        <div onClick={this.props.clickHandler.bind(this, this.props.id)}>click me</div>

【讨论】:

  • 虽然 {...this.props} 有效,但在维护一个包含数百个组件的项目之后,很难理解传递给组件的内容,这令人眼花缭乱,无法追踪。跨度>
  • @Patrick 你可以试试Redux。它引入了一个概念selector,它允许您从全局数据存储中选择道具,而不是从父级传递道具
  • Thx,redux 用于全局状态,加上它不是问题的含义。我只是特别指出,当事物嵌套时,展开运算符充其量是令人困惑的
  • 我使用 react 的时间不长,因此请谨慎对待,但如果您尝试将组件解耦并重用它们,这对我来说似乎是一种反模式。这种模式使它们依赖于具有特定命名属性的父对象的子对象。
  • 这个臭,今天有个名字——道具钻,是反花纹
【解决方案3】:

如果你想区分最后点击的是哪个元素,你可以使用 Event 对象并在其中找到一些有趣的东西,例如 DOM 元素类型。

<AnElement>
 <button onClick={e => this.eventHandler(e)}>Click me</button>
 <input type="text" onClick={e => this.eventHandler(e)}>Click me</input>

eventHandler = (e) => {
        console.log(e, e.nativeEvent.toElement.nodeName);
...}

您会得到按钮输入,具体取决于您点击的内容。 这就是我为我的项目寻找的东西。

你可能会在数组表示中找到一个 DOM 树

希望对你有帮助

【讨论】:

    猜你喜欢
    • 2014-07-26
    • 1970-01-01
    • 2016-12-01
    • 1970-01-01
    • 2014-08-26
    • 2012-12-18
    • 2018-08-24
    • 1970-01-01
    相关资源
    最近更新 更多