带有绑定事件的无元素组件

时间:2016-03-14 18:48:46

标签: reactjs

是否有React方法来创建绑定DOM事件的另一个元素的包装器组件,而不生成另一个元素(如<div>中所述)?

E.g。

class TripleClickWrapper extends Component {
  render() {
    return <div onClick={::this._onClick}>{this.props.children}</div>
  }

  _onClick() { /* counts clicks and handles timeouts etc */ }
}

// somewhere else:

<TripleClickWrapper onTripleClick={::this._doSomething}>
  <SomeComponent />
</TripleClickWrapper>

我不希望额外的<div> TripleClickWrapper创建,但我希望将onClick绑定到包装器,而不将其传递给<SomeComponent>。没有到达DOM y(findDOMNode + addEventLisetener +删除取消)的任何好方法?

如果我不需要绑定DOM事件,我可以返回React.Children.only(this.props.children)

3 个答案:

答案 0 :(得分:2)

您可以在渲染函数中返回子组件的扩充/克隆版本:https://facebook.github.io/react/docs/top-level-api.html#react.cloneelement

您可以在克隆过程中添加其他道具。

render() {
    const newProps = /* any props/event handlers you want to add */;
    return React.cloneElement(React.Children.only(this.props.children), newProps);
}

答案 1 :(得分:1)

基于源代码(具体来说,这一行:https://github.com/facebook/react/blob/v15.0.0-rc.2/src/renderers/dom/shared/ReactDOMComponent.js#L621)我看到一个可能的解决方案可能是注入一个EventPlugin。这是因为enqueuePutListener被调用,而后者又调用ReactBrowserEventEmitter.listenTo - &gt; ReactEventListener.trapBubbledEvent - &gt;实际EventListener.listen的{​​{1}}。那里的addEventListener语句会查找插件名称。我不确定该机制是如何工作的,并且在文档中没有找到它,但是有些调查听起来像是一种可能的解决方案。例如,当300ms延迟仍然存在时,有一个插件可以处理点击事件。

答案 2 :(得分:0)

我最终采用了这种方法:

  • 我不想要额外的<div>
  • 我不希望我的包装器覆盖孩子的事件(所以如果我的包裹的div已经有onClick它仍然应该运行
  • 我不想在addEventListener上手动使用findDOMNode(this)。理由:1)内部onClick无法运行e.stopPropagation()并停止我添加的事件,因为React事件在document上运行,没有useCapture,以及2)失去React事件系统的好东西。

目前我正在使用包装器中的唯一孩子并使用cloneElement,正如@Calvin Belden推荐的那样,并将我的事件与现有事件相结合。

render() {
  const onlyChild = React.Children.only(children)

  const events = {
    onClick: this.doSomething,
    onMouseEnter: this.doSomethingElse,
    // ...
  }

  for (let [eventName, fn] of Object.entries(events)) {
    if (onlyChild.props[eventName]) {
      let oldFn = onlyChild.props[eventName]
      events[eventName] = e => {
        oldFn(e)
        if (!e.isPropagationStopped()) fn(e)
      }
    }
  }

  return React.cloneElement(onlyChild, events)
}

当我使用组件而不是div时,它仍然强迫我传递事件:<TripleClickWrapper><SomeComponent></TripleClickWrapper>SomeComponent必须将onClick传递给它的div。

不是最佳,但尽可能干净。